1.6 Java全栈开发前端+后端(全栈工程师进阶之路)-前置课程Jdbc编程,使用Java通过Jdbc对数据库进行基础操作

news2024/11/18 1:29:45

原理图

用java代码实现连接数据库(mysql)的操作

因为数据库连接需要使用到APIURL,下面简单介绍下API和URL的概念,

API:

Application Programming Interface应用程序编程接口,就是一套类库

Java中的API包括三个元素: API字节码、API源码、 API帮助文档

以上三个元素的版本要保持一致

例如:JDK1.8源码、JDK1.8字节码 和JDK1.8帮助文档,三者的版本要保持一致

URL

连接数据库时,需要使用URL连接,那么,什么是URL?

URl定义:

统一资源定位系统(uniform resource locator;URL)是因特网的万维网服务程序上用于指定信息位置的表示方法。它最初是由蒂姆·伯纳斯·李发明用来作为万维网的地址。现在它已经被万维网联盟编制为互联网标准RFC1738。(百度百科)

URL是统一资源定位符,代表网络中的某个资源的绝对路径

通过URL可以定位网络中的资源

URL主要包含四部分:协议、IP、端口号和资源名称

协议是: 提前制定好的通信数据格式、规范,按照这种特定格式发送数据包,对方收到数据包之后,也按照这种规范解析这个数据包,获取有价值数据

IP作用: 定位计算机

端口号作用: 定位服务

数据库中的URL:

如:MySQL

MySQL数据库:jdbc:mysql://localhost:3366/databaseName
a、jdbc:mysql://表示协议
b、localhost表示IP
c、3366表示端口号
d、databaseName表示数据库名称

SQL的分类

数据库查询语言(DQL)
简称:DQL,Data Query Language
代表关键字:select
DQL主要是查询表中的数据

数据库操作语言(DML)
简称:DML,Data Manipulation Language
代表关键字:insert、delete 、update
DML主要是增、删、改表中的数据

数据库定义语言(DDL)
简称:DDL,Data Denifition Language
代表关键字:create、drop、alter
DDL主要是创建、删除、修改表的结构

事务控制语言(TCL)
简称:TCL,Trasactional Control Language
代表关键字:commit、rollback
TCL主要是对jdbc中的事务进行提交和回滚操作

数据控制语言(DCL)
简称:DCL,Data Control Language
代表关键字:grant、revoke

DML和DDL的区别是什么
DML是数据库操作语言,主要是修改数据库表中的数据,而DDL是数据库定义语言,主要修改数据中表的结构

JDBC编程六步曲

需要mysql驱动依赖:

        <dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
           <version>8.0.15</version>
        </dependency>

第一步:注册驱动

  • 创建驱动对象,告知JDBC我们即将连接哪个数据库

  • 通过DriverManager.registerDriver(driver)注册驱动

  •         /**
         * <p>
         * 第一步:注册驱动
         * 通过创建驱动对象告知JDBC,我们即将连接哪个厂商的数据库
         * <p/>
         *
         * @param
         * @return void
         * @Date 2020/6/7 11:23
         */
        public static void registerDriver() {
            try {
                //注册驱动(new com.mysql.jdbc.Driver()也是可以的)
                Driver driver = new com.mysql.cj.jdbc.Driver();
                DriverManager.registerDriver(driver);
    
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    

    第二步:获取数据库连接

  • 通过DriverManager.getConnection(url,user,pwd)获取连接

  • Connection连接对象不能随意创建,最后使用完要手动关闭

        /**
     * <p>
     * 第二步:获取数据库连接
     * 注意:Connection连接对象不能随意创建,最后使用完需要手动关闭
     * <p/>
     *
     * @param
     * @return java.sql.Connection
     * @Date 2020/6/7 11:24
     */
    public static Connection getConnection() {
        try {
            //注册驱动
            registerDriver();

            //获取数据库连接
            //url统一资源定位
            String url = "jdbc:mysql://ip:3306/test";
            String userName = "zhangsan";
            String passWord = "zhangsan@";
            Connection connection = DriverManager.getConnection(url, userName, passWord);

            //打印Connection对象的内存地址:com.mysql.cj.jdbc.ConnectionImpl@69d9c55
            System.out.println("MySql数据库,对java.sql.Connection接口的实现类的完整类名:" + connection);
            return connection;
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return null;
    }

MySQL数据库默认支持的最多连接数量为100 我们大家都知道MySQL最大连接数的默认值是100,这个数值对于高并发下的应用是远远不够的,当连接请求大于默认连接数后,就会出现无法连接数据库的错误,因此我们需要把它适当调大一些。

在使用MySQL数据库的时候,经常会遇到这么一个问题,就是“Can not connect to MySQL server. Too many connections”-mysql 1040错误,这是因为访问MySQL且还未释放的连接数目已经达到MySQL的上限。通常,mysql的最大连接数默认是100,最大可以达到16384。

MySQL查看最大连接数和修改最大连接数:

查看最大连接数

show variables like '%max_connections%';

修改最大连接数

set GLOBAL max_connections = 2000;

也可以通过修改配置文件来修改mysql最大连接数(max_connections),这种方式说来很简单,只要修改MySQL配置文件my.ini或my.cnf的参数max_connections,将其改为max_connections=2000,然后重启MySQL即可。

第三步:获取数据库操作对象

  • 一个数据库连接对象可以创建多个数据库操作对象

  • 通过conn.createStatement()获取数据库操作对象

        /**
     * <p>
     * 第三步:获取数据库操作对象
     * 拿到Statement数据库操作对象,就可以执行sql语句
     * <p/>
     *
     * @param
     * @return java.sql.Statement
     * @Date 2020/6/7 11:42
     */
    public static Statement getStatement() {
        try {
            //获取数据库连接
            Connection connection = getConnection();

            //获取数据库操作对象
            //一个连接对象,可以获取多个数据库操作对象
            Statement statementOne = connection.createStatement();
            //打印Statement对象的内存地址:com.mysql.cj.jdbc.StatementImpl@23f7d05d
            System.out.println("MySql数据库,对java.sql.Statement接口的实现类的完整类名:" + statementOne);

            //打印Statement对象的内存地址:com.mysql.cj.jdbc.StatementImpl@1e730495
            //Statement statementTwo = connection.createStatement();
            //System.out.println("MySql数据库,对java.sql.Statement接口的实现类的完整类名:" + statementTwo);

            return statementOne;
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return null;
    }

第四步:执行SQL语句

  • 通过数据库操作对象statement.executeUpdate(sql)编译执行SQL

  • JDBC编写SQL语句不需要以分号结尾

  • 数据库管理系统会将编写好的SQL语句编译并执行

        /**
     * <p>
     * 第四步:执行SQL语句
     * <p/>
     *
     * @param
     * @return void
     * @Date 2020/6/7 11:51
     */
    public static void executeSql() {
        try {
            //获取数据库操作对象
            Statement statement = getStatement();
            //执行SQL语句
            //注意:jdbc中,sql语句不需要以分好;结尾,当然,你写了也不会报错

            //定义DDL语句,这里可以创建表,但是,一般不这么玩,jdbc中,通常是写DML语句和DQL语句
            /*String sql = "CREATE TABLE `user` (\n" +
                    "  `id` bigint(32) NOT NULL auto_increment,\n" +
                    "  `userName` varchar(20) DEFAULT NULL COMMENT '用户名称',\n" +
                    "  `email` varchar(128) DEFAULT NULL COMMENT '邮箱|登录帐号',\n" +
                    "  `passWord` varchar(64) DEFAULT NULL COMMENT '密码',\n" +
                    "  `createTime` datetime DEFAULT NULL COMMENT '创建时间',\n" +
                    "  `lastLoginTime` datetime DEFAULT NULL COMMENT '最后登录时间',\n" +
                    "  `status` bigint(1) DEFAULT '1' COMMENT '1:有效,0:禁止登录',\n" +
                    "  PRIMARY KEY (`id`)\n" +
                    ") ENGINE=InnoDB DEFAULT CHARSET=utf8";*/

            //定义DML语句
            String sql = StringUtils.join("insert into `user`(`userName`,`passWord`,`status`) values(", "'lisi','123','1')");

            //将sql语句发送给数据库管理系统,数据库管理系统(DBMS)会编译并执行该sql语句
            int count = statement.executeUpdate(sql);

            System.out.println(count);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

第五步:处理查询结果集

处理查询结果集,获取当前光标指向行中的数据,有三种方式:

第一种方式:根据字段下标获取,不管数据库表中的字段是什么类型,都以字符串方式取出,JDBC所有下标都是以1开始

第二种方式:通过结果集中字段名称获取数据,该方式的程序更加健壮,建议使用

第三种方式:通过特定类型获取数据,该方式,明确知道字段的类型,可以节省类型转换花费的性能,该方式的程序更加健壮,性能更高,推荐使用

/**
     * <p>
     * 第五步:处理查询结果集
     * <p/>
     *
     * @param
     * @return void
     * @Date 2020/6/7 12:48
     */
    public static void dealResultSet() {
        try {
            //获取数据库操作对象
            Statement statement = getStatement();
            //定义DQL语句
            String sql = StringUtils.join("select * from `user` where userName = 'lisi'");

            //将sql语句发送给数据库管理系统,数据库管理系统(DBMS)会编译并执行该sql语句,把查询结果集放到ResultSet结果集对象中
            ResultSet resultSet = statement.executeQuery(sql);

            //处理查询结果集,一个Statement可以得出多个ResultSet
            //resultSet.next()方法作用:if the new current row is valid, return true. if there are no more rows, return false
            //将光标向前移动一行,如果指向当前行有记录,则返回true,若指向当前行无记录,返回false
            while (resultSet.next()) {
                //获取当前光标指向行中的数据,有三种方式:

                //第一种方式:根据字段下标获取,不管数据库表中的字段是什么类型,都以字符串方式取出
                //JDBC所有下标都是以1开始
                String id1 = resultSet.getString(1);
                String userName1 = resultSet.getString(2);
                String status1 = resultSet.getString(7);
                System.out.println("id1:" + id1 + ",用户名1:" + userName1 + ",有效状态1:" + status1);

                //第二种方式:通过结果集中字段名称获取数据,该方式的程序更加健壮,建议使用
                String id2 = resultSet.getString("id");
                String userName2 = resultSet.getString("userName");
                String status2 = resultSet.getString("status");
                System.out.println("id2:" + id2 + ",用户名2:" + userName2 + ",有效状态2:" + status2);

                //第三种方式:通过特定类型获取数据,该方式,明确知道字段的类型,可以节省类型转换花费的性能,该方式的程序更加健壮,性能更高,推荐使用
                int id3 = resultSet.getInt("id");
                String userName3 = resultSet.getString("userName");
                String status3 = resultSet.getString("status");
                System.out.println("id3:" + id3 + ",用户名3:" + userName3 + ",有效状态3:" + status3);
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

第六步:释放资源

一个Connection可以创建多个Statement,一个Statement可以得出多个ResultSet,所以先关闭ResultSet,再关闭Statement,最后关闭Connection

需要关闭ResultSet、Statement、Connection

为了保障能够释放资源,将释放代码编写到finally语句中

分别进行try catch关闭资源

DBC驱动对象的创建、连接、获取数据库操作对象,执行sql、处理结果集等,都需要消耗时间,其中,这里面涉及到的ResultSet、Statement、Connection对象,使用完了需要释放,否则,造成资源浪费,严重的,服务器宕机

在编程时,由于用MySQL语句调用数据库时,在每次执行语句前,会做一个临时的变量用来打开数据库,所以你在使用MySQL语句的时候,记得在每次调用完MySQL之后就关闭MySQL临时变量。

         //释放资源部分代码片段
    catch (SQLException e){
        e.printStackTrace();
    } finally{
        //第六步:释放资源,分别进行try catch
        //从小的开始关闭
        try {
            if (resultSet != null) {
                resultSet.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }

        try {
            if (statement != null) {
                statement.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }

        try {
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

JDBC编程六步曲小结

        /**
     * <p>
     * JDBC编程六部曲
     * 第一步:注册驱动
     * 第二步:获取数据库连接
     * 第三步:获取数据库操作对象
     * 第四步:执行SQL语句
     * 第五步:处理查询结果集
     * 第六步:释放资源
     * <p/>
     *
     * @param
     * @return void
     * @Date 2020/6/7 13:32
     */
    public static void jdbcProgram() {
        //定义数据库连接对象
        Connection connection = null;
        //定义数据库操作对象
        Statement statement = null;
        //定义处理结果集对象
        ResultSet resultSet = null;

        try {
            //第一步:注册驱动,通过创建驱动对象告知JDBC,我们即将连接哪个厂商的数据库
            //注册驱动(new com.mysql.jdbc.Driver()也是可以的)
            Driver driver = new com.mysql.cj.jdbc.Driver();
            DriverManager.registerDriver(driver);

            //第二步:获取数据库连接
            //注意:Connection连接对象不能随意创建,最后使用完需要手动关闭
            //url统一资源定位
            String url = "jdbc:mysql://ip:3306/test";
            String userName = "zhangsan";
            String passWord = "zhangsan@";
            connection = DriverManager.getConnection(url, userName, passWord);

            //第三步:获取数据库操作对象
            //一个连接对象,可以创建多个数据库操作对象
            statement = connection.createStatement();

            //第四步:执行SQL语句
            //注意:jdbc中,sql语句不需要以分好`;`结尾,当然,你写了也不会报错
            //定义DQL语句,jdbc中,通常是写DML语句和DQL语句
            String sql = StringUtils.join("select * from `user` where userName = 'lisi'");

            //将sql语句发送给数据库管理系统,数据库管理系统(DBMS)会编译并执行该sql语句,把查询结果集放到ResultSet结果集对象中
            resultSet = statement.executeQuery(sql);

            //第五步:处理查询结果集
            //处理查询结果集,一个Statement可以得出多个ResultSet
            //resultSet.next()方法作用:if the new current row is valid, return true. if there are no more rows, return false
            //将光标向前移动一行,如果指向当前行有记录,则返回true,若指向当前行无记录,返回false
            while (resultSet.next()) {
                //获取当前光标指向行中的数据(通过特定类型获取数据)
                //该方式,明确知道字段的类型,可以节省类型转换花费的性能,该方式的程序更加健壮,性能更高,推荐使用
                int id = resultSet.getInt("id");
                String name = resultSet.getString("userName");
                String status = resultSet.getString("status");
                System.out.println("id:" + id + ",用户名:" + name + ",有效状态:" + status);
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //第六步:释放资源,分别进行try catch
            //从小的开始关闭
            try {
                if (resultSet != null) {
                    resultSet.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }

            try {
                if (statement != null) {
                    statement.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }

            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }

JDBC编程六步曲优化

连接数据库的信息可在配置文件中进行配置,而不是硬编码到代码中

JDBC获取数据库连接有三种方式:

  • 通过键盘输入的方式(实际开发中也不会这样用)

  • 通过配置文件的方式(推荐使用)

  • 直接在数据库连接时,硬编码定义在程序中(不推荐)

通过键盘输入的方式(不推荐)

        /**
     * <p>
     * 通过键盘输入的方式,获取数据库连接(实际开发中也不会这样用)
     * <p/>
     *
     * @param
     * @return java.sql.Connection
     * @Date 2020/6/7 14:14
     */
    public static Connection getConnectionByStream() {
        try {
            System.out.println("----方式1-从控制台,通过键盘输入获取连接数据库的相关信息-----");

            //键盘输入
            /*InputStream inputStream = System.in;
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
            BufferedReader reader = new BufferedReader(inputStreamReader);*/
            //以上三行代码可以合为一行
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

            System.out.println("请输入数据库连接时注册驱动");
            String driver = reader.readLine();

            System.out.println("请输入数据库连接时的url");
            String url = reader.readLine();

            System.out.println("请输入数据库连接时的用户名user");
            String userName = reader.readLine();

            System.out.println("请输入数据库连接时的用户名密码");
            String passWord = reader.readLine();

            //关闭流
            reader.close();

            System.out.println("-----------------连接数据库--------------------");
            //注册驱动,这里必须是完整的类名(包名+类名)
            Class.forName(driver);
            //创建数据库连接
            Connection connection = DriverManager.getConnection(url, userName, passWord);
            return connection;
        } catch (IOException | ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }

        return null;
    }

通过配置文件的方式(推荐使用)

1、创建db.properties配置文件,内容如下

        #数据库连接配置
        db.driver=com.mysql.cj.jdbc.Driver
        db.url=jdbc:mysql://ip:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=PRC&useSSL=false
        db.username=zhangsan
        db.password=zhangsan@

2、通过FileReader fileReader = new FileReader(“db.properties”);读取配置文件

3、创建属性对象Properties pro = new Properties();

4、通过属性对象pro.load(reader)方法将配置信息读取到Map集合对象中(内存中)

5、关闭流 reader.close();

6、通过属性对象的getProperty(String key)方法获取配置文件中的value属性值

7、通过获取到的连接信息,创建数据库连接

        /**
     * <p>
     * 通过配置文件的方式,获取数据库连接(推荐使用)
     * <p/>
     *
     * @param
     * @return java.sql.Connection
     * @Date 2020/6/7 14:14
     */
    public static Connection getConnectionByConfiguration() {
        try {
            System.out.println("-----------方式2-读取配置文件---------------");

            //1.读取配置文件
            InputStream inputStream = JDBCTest002.class.getClassLoader().getResourceAsStream("db.properties");
            //2.创建属性对象
            Properties pro = new Properties();
            //3.通过属性对象的load()方法将配置文件读取到流中(Map集合对象中(内存中))
            pro.load(inputStream);
            //4.关闭流
            inputStream.close();
            //5.通过属性对象的getProperty(String key)方法获取配置文件中的value属性值
            String driver = pro.getProperty("db.driver");
            String url = pro.getProperty("db.url");
            String userName = pro.getProperty("db.username");
            String passWord = pro.getProperty("db.password");

            System.out.println("-----------------连接数据库--------------------");
            //注册驱动,这里必须是完整的类名(包名+类名)
            Class.forName(driver);
            //创建数据库连接
            Connection connection = DriverManager.getConnection(url, userName, passWord);
            return connection;
        } catch (IOException | ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }

        return null;
    }

数据库连接时,硬编码在程序中(不推荐)

         //第二步:获取数据库连接
         //注意:Connection连接对象不能随意创建,最后使用完需要手动关闭
         //url统一资源定位
         String url = "jdbc:mysql://ip:3306/test";
         String userName = "zhangsan";
         String passWord = "zhangsan@";
         connection = DriverManager.getConnection(url, userName, passWord);

Statement 和 PreparedStatement

JDBC中,Statement 和 PreparedStatement这两个都是数据库操作对象,都可以操作sql获取到想要的结果,但是,这两个还是有一些差别。

SQL注入现象

SQL注入定义

定义

SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。

SQL是操作数据库数据的结构化查询语言,网页的应用数据和后台数据库中的数据进行交互时会采用SQL。而SQL注入是将Web页面的原URL、表单域或数据包输入的参数,修改拼接成SQL语句,传递给Web服务器,进而传给数据库服务器以执行数据库命令。如Web应用程序的开发人员对用户所输入的数据或cookie等内容不进行过滤或验证(即存在注入点)就直接传输给数据库,就可能导致拼接的SQL被执行,获取对数据库的信息以及提权,发生SQL注入攻击。 (百度百科)

SQL注入实例

假设有一个场景: 用户通过进行用户名称,进行精确查询,用户输入的信息中有SQL关键字,并且参与了SQL语句的编译,导致SQL语句含义扭曲,最终导致了SQL注入。用户本来只应该查询到他自己的信息,但是却查出来了所有的用户信息。

SQL注入,简单来说,就是用一些SQL关键字,来导致一些不正常的现象,下面的这条sql,由于and优先级高于or,在用户录入userName = 'lisi' or 'hello' = 'hello'信息进行查询时,执行时sql就变成了select * from user where status = 1 and userName = 'lisi' or 'hello' = 'hello',导致SQL语句条件永远为真,会查出所有的用户信息数据。

select * from `user` where status = 1 and userName = {userName }

以上SQL注入原因分析: 由于and优先级高于or,该条sql最终执行时,查询条件被分为两部分(status = 1 and userName = 'lisi') or 'hello' = 'hello',导致SQL语句条件永远为真,会查出所有的用户信息数据。

如何解决SQL注入呢

定义SQL语句框架的时候,使用PreparedStatement数据库操作对象,这个是预编译对象,先将SQL语句框架进行了编译,然后给参数?动态赋值

先定义 SQL 语句构架,然后对SQL语句进行预先编译,select * from user where status = ? and userName = ? ps = conn.prepareStatement(sql);

然后再接收用户提供的信息,即使用户提供的信息中包含SQL关键字,这些关键字也不参 与编译,是不起作用的。

主要修改的部分:

通过日志也可以看出,即使用户提供的信息中包含SQL关键字,这些关键字也不参

与编译,是不起作用的

预编译SQL:select * from user where status = ? and userName = ?

赋值后,编译的SQL: select * from user where status = ‘1’ and userName = ‘\'lisi\' or \'hello\' = \'hello\'’,其实编译后的sql,是把用户录入的'lisi' or 'hello' = 'hello',整体作为了一个字符串,即执行的sql是:select * from user where status = ‘1’ and userName = “'lisi\' or \'hello\' = \'hello\'”,这样就不会发生SQL注入问题了。

Statement 和 PreparedStatement 对比

PreparedStatement可以防止 SQL 注入,执行效率高

SQL语句对于Statement来说是:编译一次执行一次

SQL语句对于PreparedStatement来说,是编译一次执行N次

原因:数据库管理系统(DBMS)厂商实现了JDBC接口,DBMS将编译后的SQL语句保存在DBMS中,由于DBMS中有很多编译好的SQL语句,这时通过同一个PreparedStatement对象进行赋值,便会找到其对应的PreparedStatement对象,从而实现其参数的赋值,即:一次编译多次执行。

PreparedStatement是类型安全的,编译期可以检查传入参数类型

JDBC事务

事务的定义

事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并用形如begin transaction和end transaction语句(或函数调用)来界定。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。

事务是恢复和并发控制的基本单位

事务的四个特性

事务应该具有4个属性:原子性、一致性、隔离性、持久性,这四个属性通常称为ACID特性。

原子性(atomicity)

一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做。

一致性(consistency)

事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。

隔离性(isolation)

一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

持久性(durability)

持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

JDBC中的事务

操作数据库时,肯定会有事务的存在,那么,JDBC中的事务是怎么使用的呢?

  • JDBC默认情况下,事务是自动提交的:即在JDBC中执行一条DML语句就执行了一次事务

  • 将事务的自动提交,修改为手动提交即可避免自动提交

  • 在事务执行的过程中,任何一步出现异常都要进行回滚

JDBC中使用事务只有三行代码:

  • 设置手动提交事务:conn.setAutoCommit(false);

  • 事务提交:conn.commit();

  • 事务回滚:conn.rollback();

在获取数据库连接后面开启事务,在 catch 语句块中进行事务回滚

JDBC编程六步曲最终版

经过以上详细的介绍,相信童鞋们也对JDBC编程有了详细的认识,下面,给出最终版的JDBC编程六部曲代码,以后使用的时候,可以直接copy,进行简单修改即可。

        /**
     * <p>
     * JDBC编程六部曲
     * 第一步:注册驱动
     * 第二步:获取数据库连接
     * 第三步:获取数据库操作对象
     * 第四步:执行SQL语句
     * 第五步:处理查询结果集
     * 第六步:释放资源
     * <p/>
     *
     * @param
     * @return void
     * @Date 2020/6/7 15:50
     */
    public static void jdbcProgramFinal() {
        //定义数据库连接对象
        Connection connection = null;
        //定义数据库操作对象
        PreparedStatement preparedStatement = null;
        //定义处理结果集对象
        ResultSet resultSet = null;

        try {
            //第一步:注册驱动,通过创建驱动对象告知JDBC,我们即将连接哪个厂商的数据库
            //注册驱动(new com.mysql.jdbc.Driver()也是可以的)
           /* Driver driver = new com.mysql.cj.jdbc.Driver();
            DriverManager.registerDriver(driver);*/

            //第二步:获取数据库连接(这里面已经注册过驱动了,如果使用这种方式,上面就不用注册驱动了)
            //注意:Connection连接对象不能随意创建,最后使用完需要手动关闭
            //通过配置文件的方式(推荐使用)
            connection = getConnectionByConfiguration();

            //第三步:获取数据库操作对象(一个连接对象,可以创建多个数据库操作对象)
            if (connection == null) {
                System.out.println("获取数据库连接失败!");
                return;
            }

            //定义DQL语句,jdbc中,通常是写DML语句和DQL语句
            //定义SQL语句框架
            String sql = StringUtils.join("select * from `user` where status = ? and userName = ?");
            //执行到此,先将SQL语句框架进行了编译
            preparedStatement = connection.prepareStatement(sql);
            //这里假设是前台传的参数值
            String statusParam = "1";
            String userNameParam = "'lisi' or 'hello' = 'hello'";
            //给参数?动态赋值
            preparedStatement.setString(1, statusParam);
            preparedStatement.setString(2, userNameParam);

                        //打印预编译SQL
            //System.out.println("预编译SQL:" + ((ClientPreparedStatement) preparedStatement).getPreparedSql());
            //打印赋值后,编译的SQL
            //System.out.println("赋值后,编译的SQL:" + ((ClientPreparedStatement) preparedStatement).asSql());

            //第四步:执行SQL语句
            //将sql语句发送给数据库管理系统,数据库管理系统(DBMS)会编译并执行该sql语句,把查询结果集放到ResultSet结果集对象中
            resultSet = preparedStatement.executeQuery();

            //第五步:处理查询结果集
            //处理查询结果集,一个Statement可以得出多个ResultSet
            //resultSet.next()方法作用:if the new current row is valid, return true. if there are no more rows, return false
            //将光标向前移动一行,如果指向当前行有记录,则返回true,若指向当前行无记录,返回false
            while (resultSet.next()) {
                //获取当前光标指向行中的数据(通过特定类型获取数据),该方式,明确知道字段的类型,可以节省类型转换花费的性能,该方式的程序更加健壮,性能更高,推荐使用
                int id = resultSet.getInt("id");
                String name = resultSet.getString("userName");
                String status = resultSet.getString("status");
                System.out.println("id:" + id + ",用户名:" + name + ",有效状态:" + status);
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //第六步:释放资源,从小的开始关闭,分别进行try catch
            try {
                if (resultSet != null) {
                    resultSet.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }

            try {
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }

            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * <p>
     * 通过配置文件的方式,获取数据库连接(推荐使用)
     * <p/>
     *
     * @param
     * @return java.sql.Connection
     * @Date 2020/6/7 14:14
     */
    public static Connection getConnectionByConfiguration() {
        try {
            //1.读取配置文件
            InputStream inputStream = JDBCTest003.class.getClassLoader().getResourceAsStream("db.properties");
            //2.创建属性对象
            Properties pro = new Properties();
            //3.通过属性对象的load()方法将配置文件读取到流中(Map集合对象中(内存中))
            pro.load(inputStream);
            //4.关闭流
            inputStream.close();
            //5.通过属性对象的getProperty(String key)方法获取配置文件中的value属性值
            String driver = pro.getProperty("db.driver");
            String url = pro.getProperty("db.url");
            String userName = pro.getProperty("db.username");
            String passWord = pro.getProperty("db.password");

            //注册驱动,这里必须是完整的类名(包名+类名)
            Class.forName(driver);
            //创建数据库连接
            Connection connection = DriverManager.getConnection(url, userName, passWord);
            return connection;
        } catch (IOException | ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }

        return null;
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1637411.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024中国绿电制氢技术趋势分析报告

来源&#xff1a;ATC & 大东时代 国家级规划《氢能产业发展中长期规划&#xff08;2021-2035&#xff09;》出台 • 主要宗旨&#xff1a;明确“能源”的角色定位以及在绿色低碳转型中的作用&#xff0c;为产业发展构建清晰的蓝图。 • 阶段目标设立&#xff1a; • 2025/…

如何不使用代理服务从hugging face上下载大模型?

前言&#xff1a;中国大陆的朋友会发现hugging face经常无法访问了&#xff0c;特别是在服务器上下载大型模型/数据集&#xff0c;如果先在电脑上下载完再传输到服务器上&#xff0c;对于大模型来说会非常麻烦&#xff0c;这篇博客一共提供了三种有效的方法不使用代理服务从hug…

【Java】何为JShell?——有趣的Java学习小工具

前言&#xff1a;上一篇中我们已经看到了如何编译和运行一个Java程序。Java1.9&#xff08;即Java9&#xff09;中引入了另一种使用Java的方式。JShell(Java Shell)程序提供了一个“读取-计算-打印循环”&#xff08;Read-Evaluate-Print Loop,REPL&#xff09;。当你键入一个J…

【综述】多核处理器芯片

文章目录 前言 Infineon处理器 AURIX™系列 TC399XX-256F300S 典型应用 开发工具 参考资料 前言 见《【综述】DSP处理器芯片》 Infineon处理器 AURIX™系列&#xff0c;基于TriCore内核&#xff0c;用于汽车和工业领域。 XMC™系列&#xff0c;基于ARM Cortex-M内核&…

基于 Evan_song1234 开发,MoonSpaceCat 增补的2D 我的世界,增加双缓冲实现 cmd控制台窗口或 Powershell 流畅运行

游戏玩法&#xff1a; awsd移动 1234567890 各有功能 t 是命令行 q 是刷新 e 是重开 z 是挖 其他还没来及探索代码 代码来源 C我的世界2D控制台版_cminecraft-CSDN博客 其中解决颜色被双缓冲刷新没的方法 参考于自己的博客 用ReadConsoleOutput 解决双缓冲ReadConsol…

短视频素材哪个App最好?短视频素材哪里有免费的?

在数字媒体的黄金时代&#xff0c;富有创意的视频内容已成为吸引观众的关键。高质量的视频素材不仅能增强视觉效果&#xff0c;还能提升整体叙述的力度。以下列出了一系列全球顶尖的视频素材提供网站&#xff0c;它们将为你的广告制作、社交媒体或任何视频项目提供极具影响力的…

Python制作精美表格——plottable

plottable是一个基础matplotlib的绘制精美图形表格的库。他将表格内容美化并转为一张图片 使用前提&#xff1a; 1、原始数据数量较少&#xff0c;可以一屏展示。这个库会将原始表格的所有数据都放到一个图片里&#xff0c;数据太多展示效果较差。 2、pandas读取时会将index列…

vue3步骤条带边框点击切换高亮

如果是div使用clip-path: polygon(0% 0%, 92% 0%, 100% 50%, 92% 100%, 0% 100%, 8% 50%);进行裁剪加边框没实现成功。目前这个使用svg完成带边框的。 形状可自行更改path 标签里的 :d“[num ! 1 ? ‘M 0 0 L 160 0 L 176 18 L 160 38 L 0 38 L 15.5 18 Z’ : ‘M 0,0 L 160,0…

飞腾D2000+X100 TYPE6全国产核心板

飞腾D2000X100 TYPE6核心板 产品概述 飞腾D2000X100 TYPE6核心板为增强型自主控制器核心板&#xff0c;其核心芯片CPU采用飞腾D2000/8核工业版CPU、飞腾桥片X100、双通道DDR4L插槽、PHY芯片等。 产品特点 l 基于飞腾D2000X100桥片 l 丰富的PCIE扩展资源&#xff0c;一路PCIE…

Java设计模式 _结构型模式_过滤器模式

一、过滤器模式 1、过滤器模式 过滤器模式&#xff08;Filter Pattern&#xff09;是这一种结构型设计模式。过滤器&#xff0c;顾名思义&#xff0c;就是对一组数据进行过滤&#xff0c;从而最终获取到我们预期的数据。 2、实现思路 &#xff08;1&#xff09;、定义过滤器的…

图搜索算法详解与示例代码

在计算机科学领域&#xff0c;图搜索算法是一类用于在图数据结构中查找特定节点或路径的算法。图搜索算法在许多领域都有着广泛的应用&#xff0c;包括网络路由、社交网络分析、游戏开发等。本文将详细介绍几种常见的图搜索算法&#xff0c;包括深度优先搜索&#xff08;DFS&am…

数据结构四:线性表之带头结点的单向循环链表的设计

前面两篇介绍了线性表的顺序和链式存储结构&#xff0c;其中链式存储结构为单向链表&#xff08;即一个方向的有限长度、不循环的链表&#xff09;&#xff0c;对于单链表&#xff0c;由于每个节点只存储了向后的结点的地址&#xff0c;到了尾巴结点就停止了向后链的操作。也就…

LeetCode 98.验证二叉搜索树

题目描述 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左 子树 只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。 示例 1&#xff…

服务端不 listen 可以创建 tcp 连接吗

这个问题有三类答案。 上来就撸 linux kernel 源码&#xff0c;折腾半天&#xff0c;哦&#xff0c;终于在 tcp_rcv_state_process 里找到了 tcp_rcv_synsent_state_process 调用&#xff0c;后者包含&#xff1a; if (th->syn) {/* We see SYN without ACK. It is attemp…

如何 “ 一劳永逸 ” 去掉引用网址的小尾巴

引用文章的链接时会出现很长冗余信息&#xff0c;删&#xff0c;删&#xff0c;删……&#xff0c;直到从平流层删到地平线 示例链接 使用 Neat URL&#xff08;支持 google 系、Firefox&#xff09;扩展中的【拦截参数】可以去除的这类百无聊赖的小尾巴。 安装后&#xff…

信创 | 信创中间件全览:核心种类与关键组件!

信创产业中的中间件主要包括基础中间件和广义中间件两大类。基础中间件包括交易中间件、消息中间件、应用服务器中间件等&#xff0c;而广义中间件则涵盖了更多种类的中间件产品&#xff0c;以适应不断变化的技术需求。 一、常用的信创中间件包含&#xff1a; 交易中间件&…

20232937文兆宇 2023-2024-2 《网络攻防实践》实践八报告

20232937文兆宇 2023-2024-2 《网络攻防实践》实践八报告 1.实践内容 动手实践任务一 对提供的rada恶意代码样本&#xff0c;进行文件类型识别&#xff0c;脱壳与字符串提取&#xff0c;以获得rada恶意代码的编写作者&#xff0c;具体操作如下&#xff1a; &#xff08;1&am…

Eclipse MAT工具分析内存溢出

1、通过dominator_tree可以查看哪些对象大 可以看到com.codex.terry.entity.User对象有57万个 2、打开thread_overview查看内存溢出的代码

PyVista 3D数据可视化 Python 库 简介 含源码

Pyvista是一个用于科学可视化和分析的Python库 &#xff1b;我认为它适合做一些网格数据的处理&#xff1b; 它封装了VTK&#xff08;Visualization Toolkit&#xff09;之上&#xff0c;提供了一些高级接口&#xff0c; 3D数据可视化变得更加简单和易用。 1.安装 pyvista&…

表格中斜线的处理

此处的斜线,不是用表格写的,但是也适用于表格,只是需要更改表格的样式,可以 按照如下处理,即可 呈现的效果:如图所示 template部分: <div class"header_detail custom"><div class"right">节次</div><div class"left">…