蓝旭后端第七次培训课 JDBC

目录

一、什么是JDBC

二、Hello JDBC

1.为项目导入mysql-jdbc依赖的jar包

2.初始化驱动

3.建立与数据库的连接

4.创建statement

5.执行SQL语句

6.关闭连接

小插曲:Java7语法糖-------try-with-resources

三、查询

四、预编译Statement

五、execute方法,executeUpdate方法与executeQuery方法

六、特殊操作

七、事务

八、ORM

九、DAO


一、什么是JDBC

JDBC的全称是Java数据库连接(Java Database Connect),它是一套用于执行SQL语句的Java API。应用程序可通过这套API连接到关系数据库,并使用SQL语句来完成对数据库中数据的查询、更新和删除等操作。

二、Hello JDBC

1.为项目导入mysql-jdbc依赖的jar包

访问MySQL数据库需要用到第三方的类,这些第三方的类,都被压缩在一个叫做Jar的文件里。为了代码能够使用第三方的类,需要为项目导入mysql的专用Jar包。       

我们使用的是mysql-connector-java-8.0.11-bin.jar的驱动,当然也可以使用mysql-connector-java-5.1.46-bin.jar的驱动,但是在加载驱动的时候以及填写链接的时候会有些不同,后续会介绍

  • 通常都会把项目用到的jar包统一放在项目的lib目录下

类似于这样:

注意:lib文件夹要放到web-inf文件下,不然可能导致导入失败

当然不要忘记在项目结构中把这个lib添加为项目依赖,这样才算是导入了jar包

2.初始化驱动

通过Class.forName(驱动类的类路径)来进行初始化驱动

Class.forName:返回与给定的字符串名称相关联接口的Class对象。

    public static void main(String[] args) {
        try {
            // 初始化驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            System.out.println("初始化驱动加载成功");
        }catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

或者使用DriverManager.register(驱动类的对象)进行初始化驱动

DriverManager:管理一组 JDBC 驱动程序的基本服务。

作用:用于管理和注册驱动,建立与数据库的连接

    public static void main(String[] args) {
        try {
            // 初始化驱动
            DriverManager.registerDriver(new Driver());
            System.out.println("初始化驱动加载成功");
        }catch (SQLException e) {
            e.printStackTrace();
        }
    }

注意:在 mysql-connector-java-8.0.11-bin.jar中,驱动类的类路径为com.mysql.cj.jdbc.Driver,而在 mysql-connector-java-5.0.8-bin.jar中,驱动类的类路径为com.mysql.jdbc.Driver

3.建立与数据库的连接

  • 协议连接格式

协议名:子协议://IP地址或服务器名:端口号/数据库名?参数=参数值

例如:jdbc:mysql://localhost:3306/jdbc?characterEncoding=utf8&serverTimezone=GMT&useSSL=false

参数characterEncoding可以防止乱码出现,通常设置为utf8

参数serverTimezone用来设置时区,可以为GMT,也可以是中国标准时间Asia/Shanghai

参数useSSL用来设置是否使用ssl连接,目前学习jdbc不建议建立SSL连接,所以可设置为false。

  • 什么是Connection?

Connection是一个接口,用于操作数据库。具体实现有各大厂商来做。

public static void main(String[] args) {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 建立与数据库的Connection连接
            // 这里需要提供:
            // 数据库所处于的ip:127.0.0.1 或者说localhost (本机)
            // 数据库的端口号: 3306 (mysql专用端口号)
            // 数据库名称: jdbc(根据你自己的数据名称来设置)
            // 编码方式: UTF-8
            // 时区: GMT (8版本的驱动要添加,5版本可以不写)
            // 是否使用ssl连接: false (8版本的驱动要添加,5版本可以不写)
            // 账号: root(根据你自己的用户名填写)
            // 密码: root(根据你自己的密码填写)
            String url = "jdbc:mysql://localhost:3306/jdbc?characterEncoding=utf8&serverTimezone=GMT&useSSL=false";
            // String url = "jdbc:mysql://localhost:3306/jdbc?characterEncoding=utf8"; 这个是5版本的驱动使用的连接
            String username = "root";
            String password = "root";
            Connection connection = DriverManager.getConnection(url, username, password);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

 

4.创建statement

  • statement的作用是什么?

statement用于执行SQL语句的

  • 使用statement进行增删改查

首先是JDBCUtils类,封装了注册驱动,获取连接,关闭连接等方法,方便调用。

package com.jdbc.util;

import java.sql.*;

public class JDBCUtils {

    private final String url = "jdbc:mysql://localhost:3306/jdbc?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false";
    private final String username = "root";
    private final String password = "root";

    private volatile static JDBCUtils jdbcUtils = null;

    /*
      初始化驱动
     */
    static {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private Connection getMysqlConnection(JDBCUtils jdbcUtils){
        Connection connection = null;
        try {
            connection = DriverManager.getConnection(jdbcUtils.url,jdbcUtils.username,jdbcUtils.password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }

    /**
     * 获取MySQL数据连接对象(略读,不要求掌握)
     * @return Connection连接对象
     */
    public static Connection getMysqlConnection(){
        return getInstance().getMysqlConnection(getInstance());
    }

    /**
     * 获取实例对象(略读,不要求掌握)
     * @return JDBCUtils对象
     */
    private static JDBCUtils getInstance() {
        if (null == jdbcUtils){
            synchronized (JDBCUtils.class){
                if (null == jdbcUtils){
                    jdbcUtils = new JDBCUtils();
                }
            }
        }
        return jdbcUtils;
    }

    /**
     * 关闭连接
     * @param connection
     */
    public static void close(Connection connection){
        if (connection != null) {
            try {
                connection.close();
                System.out.println("连接已关闭");
            } catch (SQLException e) {
                System.out.println("连接关闭失败");
                e.printStackTrace();
            }
        }
    }

    /**
     * 关闭连接
     * @param connection
     * @param statement
     * @param resultSet
     */
    public static void close(Connection connection, Statement statement, ResultSet resultSet){
        if (resultSet != null) {
            try {
                resultSet.close();
                System.out.println("resultSet关闭成功");
            } catch (SQLException e) {
                System.out.println("resultSet关闭失败");
                e.printStackTrace();
            }
        }
        if (statement != null) {
            try {
                statement.close();
                System.out.println("statement关闭成功");
            } catch (SQLException e) {
                System.out.println("statement关闭失败");
                e.printStackTrace();
            }
        }
        if (connection != null) {
            try {
                connection.close();
                System.out.println("连接已关闭");
            } catch (SQLException e) {
                System.out.println("连接关闭失败");
                e.printStackTrace();
            }
        }
    }
}

其次是测试类

package com.jdbc.test;

import com.jdbc.util.JDBCUtils;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

public class TestStatement {
    public static void main(String[] args) {
        // 获取连接
        Connection mysqlConnection = JDBCUtils.getMysqlConnection();
        // 创建statement对象
        Statement statement = null;
        String sql = null;
        boolean execute = false;
        try {
            statement = mysqlConnection.createStatement();
            System.out.println("statement创建成功");
            
        } catch (SQLException e) {
            System.out.println("statement创建失败");
            e.printStackTrace();
        }finally {
            JDBCUtils.close(mysqlConnection,statement,null);
        }

    }
}

5.执行SQL语句

package com.jdbc.test;

import com.jdbc.util.JDBCUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestStatement {
    public static void main(String[] args) {
        // 获取连接
        Connection mysqlConnection = JDBCUtils.getMysqlConnection();
        // 创建statement对象
        Statement statement = null;
        String sql = null;
        boolean execute = false;
        try {
            statement = mysqlConnection.createStatement();
            System.out.println("statement创建成功");
            // 查
            sql = "select * from tb_user where `username` = 'Jack'";
            execute = statement.execute(sql);
            // 通过getResultSet方法可以获取返回结果集
            ResultSet resultSet = statement.getResultSet();
            while (resultSet.next()){
                System.out.println(resultSet.getInt(1));
            }
            System.out.println("select语句的execute = " + execute);
            // 增
            sql = "insert into tb_user(`username`,`password`,`gender`) values('Tom','123456',1)";
            execute = statement.execute(sql);
            System.out.println("insert语句的execute = " + execute);
            // 改
            sql = "update tb_user set `password` = '12345678' where `username` = 'Tom'";
            execute = statement.execute(sql);
            System.out.println("update语句的execute = " + execute);
            // 删
            sql = "delete from tb_user where `username` = 'Tom'";
            execute = statement.execute(sql);
            System.out.println("delete语句的execute = " + execute);
            // 方法statement.execute(sql)的返回值,如果执行的是select语句,且有返回集,则为true,其他情况下均为false。该返回值并不表示SQL语句是否执行成功
        } catch (SQLException e) {
            System.out.println("sql执行异常");
            e.printStackTrace();
        }finally {
            JDBCUtils.close(mysqlConnection,statement,null);
        }
    }
}

6.关闭连接


    /*以下是来自JDBCUtils中的关闭方法*/


    /**
     * 关闭连接
     * @param connection
     */
    public static void close(Connection connection){
        if (connection != null) {
            try {
                connection.close();
                System.out.println("连接已关闭");
            } catch (SQLException e) {
                System.out.println("连接关闭失败");
                e.printStackTrace();
            }
        }
    }

    /**
     * 关闭连接
     * @param connection
     * @param statement
     * @param resultSet
     */
    public static void close(Connection connection, Statement statement, ResultSet resultSet){
        if (resultSet != null) {
            try {
                resultSet.close();
                System.out.println("resultSet关闭成功");
            } catch (SQLException e) {
                System.out.println("resultSet关闭失败");
                e.printStackTrace();
            }
        }
        if (statement != null) {
            try {
                statement.close();
                System.out.println("statement关闭成功");
            } catch (SQLException e) {
                System.out.println("statement关闭失败");
                e.printStackTrace();
            }
        }
        if (connection != null) {
            try {
                connection.close();
                System.out.println("连接已关闭");
            } catch (SQLException e) {
                System.out.println("连接关闭失败");
                e.printStackTrace();
            }
        }
    }
}

关闭顺序为:先开启的后关闭,即关闭顺序为:resultSet>statement>connection

总结:

    jdbc的整个执行过程为:1.加载驱动 2.获取连接 3.创建语句 4.执行SQL 5.关闭连接

小插曲:Java7语法糖-------try-with-resources

语法糖(Syntactic sugar),也译为糖衣语法,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。

在 Java 7 以及后续版本中,支持 try-with-resources,任何实现 java.lang.AutoCloseable 接口的类,包括 java.io.Closeable 的实现类,都可以通过 try-with-resources 来关闭。

原来关闭资源的代码:

InputStream inputStream = null;
try {
    inputStream = new FileInputStream("/my/file");
    // ...
} catch (Exception e) {
    e.printStackTrace();
} finally {
    if (inputStream != null) {
        try {
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

使用语法糖后的代码:

try (InputStream inputStream = new FileInputStream("/my/file")) {
    // ...
} catch (Exception e) {
    e.printStackTrace();
}

 两个代码虽然长得不一样,但是对于Java虚拟机jvm来说起到的效果是相同的。验证:两段代码的字节码文件分别反编译,你会发现结果是一样的。

通过 JDBC 查询数据库时,会依次创建 ConnectionStatementResultSet,并且这三个资源都需要关闭,那么可以这样写:

try (Connection connection = DriverManager.getConnection(url, user, password);
     Statement statement = connection.createStatement();
     ResultSet resultSet = statement.executeQuery("SELECT ...")) {
    // ...
} catch (Exception e) {
    // ...
}

多个 resources 的关闭顺序

如果在 try 中定义了多个 resources,那么它们关闭的顺序和创建的顺序是相反的。上面的例子中,依次创建了 ConnectionStatmentResultSet 对象,最终关闭时会依次关闭 ResultSetStatmentConnection,所以不用担心 Connection 会先 close。

 

三、查询

  • 查询使用的方法为:executeQuery(sql语句),返回值为ResultSet类型的对象
  • ResultSet几个必会方法:
  1. resultSet.next() 返回值为布尔类型,表示是否有下一个元素,true表示有,false表示没有

  2. resultSet.getInt(数据库字段名或者字段的位置) 返回值为int类型,表示获取查询结果集中,当前元组指定字段的数据,并且转换为int类型

同理,resultSet.getString(数据库字段名或者字段的位置) resultSet.getDouble(数据库字段名或者字段的位置) 等都是获取指定字段的数据,并且进行对应数据类型的转换

这里字段的位置是从1开始计算的

package com.jdbc.test;

import com.jdbc.util.JDBCUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestQuery {
    public static void main(String[] args) {
        Connection mysqlConnection = JDBCUtils.getMysqlConnection();
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            statement = mysqlConnection.createStatement();
            String sql = "select * from tb_user where `username` = 'Susan'";
            resultSet = statement.executeQuery(sql);
            while (resultSet.next()){
                int id = resultSet.getInt("id");
                String username = resultSet.getString(2);
                String password = resultSet.getString("password");
                int gender = resultSet.getInt(4);
                System.out.println("id = " + id);
                System.out.println("username = " + username);
                System.out.println("password = " + password);
                System.out.println("gender = " + gender);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.close(mysqlConnection,statement,resultSet);
        }
    }
}

四、预编译Statement

  • 什么是PreparedStatement?

和 Statement一样,PreparedStatement也是用来执行sql语句的

  • PreparedStatement和Statement有什么区别?

  1. 需要根据sql语句创建PreparedStatement,而statement不需要

  2. PreparedStatement可以通过设置参数,指定相应的值,而不是Statement那样使用字符串拼接(注意,这里参数的位置是从1开始计算的

  3. PreparedStatement有预编译机制,而Statement没有

  • 既然有Statement,为什么还要有PreparedStatement呢,或者说PreparedStatement的优点是什么呢?
  1. PreparedStatement的参数设置相比于Statement来说更加容易维护,可读性更高,不容易犯错

  2. PreparedStatement的预编译机制,性能比Statement更快

  3. PreparedStatement可以防止SQL注入式攻击

package com.jdbc.test;

import com.jdbc.entity.User;
import com.jdbc.util.JDBCUtils;

import java.sql.*;

public class TestPrepareStatement {
    /**
     * preparedStatement的参数设置
     * @param user
     */
    public void userRegister1(User user){
        Connection mysqlConnection = JDBCUtils.getMysqlConnection();
        String sqlOne = "insert into tb_user(`username`,`password`,`gender`) values("+user.getUsername()+","+user.getPassword()+","+user.getGender()+")";
        String sqlTwo = "insert into tb_user(`username`,`password`,`gender`) values(?,?,?)";
        try (
                Statement statement = mysqlConnection.createStatement();
                PreparedStatement prepareStatement = mysqlConnection.prepareStatement(sqlTwo);
        ){
            statement.execute(sqlOne);
            // 参数设置是从1开始的,不是从0开始的
            prepareStatement.setString(1,user.getUsername());
            prepareStatement.setString(2,user.getPassword());
            prepareStatement.setInt(3,user.getGender());
            prepareStatement.execute();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.close(mysqlConnection);
        }
    }

    /**
     * preparedStatement的预编译机制
     * @param user
     */
    public void userRegister2(User user){
        Connection mysqlConnection = JDBCUtils.getMysqlConnection();
        String sqlOne = "insert into tb_user(`username`,`password`,`gender`) values("+"\""+user.getUsername()+"\""+","+user.getPassword()+","+user.getGender()+")";
        String sqlTwo = "insert into tb_user(`username`,`password`,`gender`) values(?,?,?)";
        try (
                Statement statement = mysqlConnection.createStatement();
                PreparedStatement prepareStatement = mysqlConnection.prepareStatement(sqlTwo);
        ){
            // 插入十个用户,statement需要执行10次sql语句,需要10都把SQL语句传输到数据库端,数据库每次都要对SQL语句进行编译的执行
            for (int i = 0; i < 10; i++) {
                statement.execute(sqlOne);
            }
            // 插入十个用户,PreparedStatement 执行10次,只需要1次把SQL语句传输到数据库端
            // 数据库对带?的SQL进行预编译
            // 每次执行,只需要传输参数到数据库端
            // 1. 网络传输量比Statement更小
            // 2. 数据库不需要再进行编译,响应更快
            for (int i = 0; i < 10; i++) {
                prepareStatement.setString(1,user.getUsername());
                prepareStatement.setString(2,user.getPassword());
                prepareStatement.setInt(3,user.getGender());
                prepareStatement.execute();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.close(mysqlConnection);
        }
    }

    /**
     * 防止SQL注入
     * @param user
     */
    public void userRegister3(User user){
        Connection mysqlConnection = JDBCUtils.getMysqlConnection();
        String sqlOne = "select * from tb_user where `username` = "+user.getUsername();
        String sqlTwo = "select * from tb_user where `username` = ?";
        ResultSet resultSet = null;
        try (
//                Statement statement = mysqlConnection.createStatement();
                PreparedStatement prepareStatement = mysqlConnection.prepareStatement(sqlTwo);
        ){
//            ResultSet resultSet = statement.executeQuery(sqlOne);
            // PreparedStatement会对SQL进行了预编译,在第一次执行SQL前数据库会进行分析、编译和优化,同时执行计划同样会被缓存起来,它允许数据库做参数化查询。
            // 在使用参数化查询的情况下,数据库不会将参数的内容视为SQL执行的一部分,而是作为一个字段的属性值来处理,这样就算参数中包含破环性语句(or ‘1=1’)也不会被执行。
            // preparedStatement执行的SQL语句:select * from tb_user where `username` = "'Jack' or 1=1"
            prepareStatement.setString(1,user.getUsername());
            resultSet = prepareStatement.executeQuery();
            while (resultSet.next()){
                user.setId(resultSet.getInt("id"));
                user.setUsername(resultSet.getString("username"));
                user.setPassword(resultSet.getString("password"));
                user.setGender(resultSet.getInt("gender"));
                System.out.println(user);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.close(mysqlConnection,null,resultSet);
        }
    }
    public static void main(String[] args) {
        User user = new User();
        user.setUsername("Jack");
        user.setPassword("123");
        user.setGender(1);
        TestPrepareStatement testPrepareStatement = new TestPrepareStatement();
        // 优点1演示
//        testPrepareStatement.userRegister1(user);
        // 优点2演示
//        testPrepareStatement.userRegister2(user);
        // 优点3演示
        // statement会把数据库中所有的信息查出来,而preparedStatement返回集为空
//        user.setUsername("'Jack' or 1=1");
//        testPrepareStatement.userRegister3(user);
    }
}

 

五、execute方法,executeUpdate方法与executeQuery方法

  • execute方法可以执行任何SQL语句,返回类型为布尔类型,若有结果集则为true,否则为false
  • executeUpdate方法只可以执行DML数据操纵语言和DDL数据定义语言,返回受影响的行数
  • executeQuery方法只可以执行DQL数据查询语言,返回值为ResultSet返回结果集

因此建议大家在使用DML数据操纵语言的时候,使用executeUpdate方法,可以根据返回值判断该语句的执行情况

六、特殊操作

  • 获取自增ID

一般情况下,MySQL数据库每张表都有一个自增ID,作为这张表的主键。向数据库插入一条数据后,MySQL会自动计算并且为ID字段赋值,接下来的操作就是介绍如何获取这个自增的ID

package com.jdbc.test;

import com.jdbc.entity.User;
import com.jdbc.util.JDBCUtils;

import java.sql.*;

public class TestSpecialOperation {

    public void userRegister(User user){
        Connection mysqlConnection = JDBCUtils.getMysqlConnection();
        PreparedStatement prepareStatement = null;
        ResultSet generatedKeys = null;
        String sql = "insert into tb_user(`username`,`password`,`gender`) values(?,?,?)";
        try {
            // 要记得加一个参数Statement.RETURN_GENERATED_KEYS,才可以返回自增主键
            prepareStatement = mysqlConnection.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
            prepareStatement.setString(1,user.getUsername());
            prepareStatement.setString(2,user.getPassword());
            prepareStatement.setInt(3,user.getGender());
            prepareStatement.execute();
            // 获取自增长id
            generatedKeys = prepareStatement.getGeneratedKeys();
            if (generatedKeys.next()){
                System.out.println("generatedKeys = " + generatedKeys.getInt(1));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.close(mysqlConnection,prepareStatement,generatedKeys);
        }
    }

    public static void main(String[] args) {
        User user = new User();
        user.setUsername("Jack");
        user.setPassword("123");
        user.setGender(1);
        TestSpecialOperation testSpecialOperation =new TestSpecialOperation();
        testSpecialOperation.userRegister(user);
    }
}

七、事务

  • 什么是事务?

数据库事务( transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。

MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你既需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!

一般来说,事务是必须满足4个条件(ACID)::原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。

原子性: 一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。

一致性: 在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。

隔离性: 数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。

持久性: 事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

  • 为什么要使用事务?

假设这样一种场景,银行汇款。A向B汇款100元(假设A账户余额大于100元),那么要实现这样的功能,需要进行的操作有:

1.A账户余额减去100元

2.B账户余额增加100元

但是,如果步骤1执行成功,但是步骤2执行出现问题,这个时候就会出现A账户减少100但是B没有收到。这个问题是很严重的,直接导致损害到了用户的利益。

因此,为了防止出现这样的情况,我就要用到事务。

上述情况,如果使用了事务,在事务中出现错误(指的是抛出运行时异常)的时候,整个执行操作都会被自动回滚(或者也可以自己调用rollback方法进行回滚)。这样的话,就保证了用户的利益。

接下来介绍一下,在jdbc中如何操作事务

package com.jdbc.test;

import com.jdbc.entity.User;
import com.jdbc.util.JDBCUtils;

import java.sql.*;

public class TestTransaction {
    public void userRegister(User user){
        Connection mysqlConnection = JDBCUtils.getMysqlConnection();
        PreparedStatement prepareStatement = null;
        ResultSet generatedKeys = null;
        String sql1 = "insert into tb_user(`username`,`password`,`gender`) values(?,?,?)";
        String sql2 = "update tb_user set `password` = ? where `id` = ?";
        try {
            // 设置取消自动提交
            mysqlConnection.setAutoCommit(false);
            prepareStatement = mysqlConnection.prepareStatement(sql1, Statement.RETURN_GENERATED_KEYS);
            prepareStatement.setString(1,user.getUsername());
            prepareStatement.setString(2,user.getPassword());
            prepareStatement.setInt(3,user.getGender());
            int num = prepareStatement.executeUpdate();
            if (num == 1){
                generatedKeys = prepareStatement.getGeneratedKeys();
                if (generatedKeys.next()){
                    int id = generatedKeys.getInt(1);
                    prepareStatement = mysqlConnection.prepareStatement(sql2);
                    prepareStatement.setString(1,"1234");
                    prepareStatement.setInt(2,id+1);
                    int i = prepareStatement.executeUpdate();
                    if (i == 1){
                        System.out.println("更新成功");
                    }else {
//                        // 抛出运行时异常,自动回滚
//                        throw new RuntimeException("更新失败");
                        // 手动调用rollback方法回滚
                        mysqlConnection.rollback();
                        System.out.println("事务回滚");
                    }
                }
            }else {
                // 抛出运行时异常,自动回滚
                throw new RuntimeException("用户注册失败");
//                // 手动调用rollback方法回滚
//                mysqlConnection.rollback();
//                System.out.println("事务回滚");
            }
            // 手动提交
            mysqlConnection.commit();
            //mysqlConnection.setAutoCommit(false)和mysqlConnection.commit(),之间的所有操作都会被归到一个事务中
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.close(mysqlConnection,prepareStatement,generatedKeys);
        }
    }
    public static void main(String[] args) {
        User user = new User();
        user.setUsername("Jack");
        user.setPassword("123");
        user.setGender(1);
        TestTransaction testTransaction = new TestTransaction();
        testTransaction.userRegister(user);
    }
}

八、ORM

  • 什么是ORM

ORM(Object-relational mapping),中文翻译为对象关系映射,是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。

简单说,一个对象,对应数据库里的一条记录

  • 表与类的关系

一张表的表结构和一个实体类的属性一一对应

一张表的一个元组对应一个实体类的实例对象

九、DAO

DAO(Data Access Object)是一个数据访问接口,数据访问:顾名思义就是与数据库打交道。夹在业务逻辑与数据库资源中间。

简单来说,就是把和数据库打交道的逻辑,都放到DAO层,进行功能的聚合。不向外暴露与数据库交互的逻辑处理,也就是实现功能解耦。

 

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值