栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JDBC

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JDBC

JDBC
  • 01_JDBC
    • 一、概述
      • 1.1、什么是JDBC
      • 1.2、JDBC原理
    • 二、JDBC入门
      • 2.1、准备工作
        • 2.1.1、建库建表
        • 2.1.2、新建项目
      • 2.2、建立连接
        • 2.2.1、准备四大参数
        • 2.2.2、加载驱动
        • 2.2.3、准备SQL语句
        • 2.2.4、建立连接
        • 2.2.5、常见问题
      • 2.3、获取发送SQL的对象
      • 2.4、执行SQL语句
      • 2.5、处理结果
      • 2.6、释放资源
      • 2.7、完整代码
      • 2.8、上面的程序改进
      • 2.9、改进后的完整代码
    • 三、查询操作
      • 3.1、获取结果集
      • 3.2、处理结果集
      • 3.3、查询操作完整代码
    • 四、PreparedStatement
      • 4.1、SQL注入
        • 4.1.1、什么是SQL注入
        • 4.1.2、SQL注入案例
        • 4.1.3、如何避免SQL注入
      • 4.2、PreparedStatement使用
        • 4.2.1、预编译SQL语句
        • 4.2.2、设置参数
        • 4.2.3、完整代码
    • 五、使用JDBC进行CRUD操作(掌握)
      • 5.1、添加操作
      • 5.2、删除操作
      • 5.3、修改操作
      • 5.4、查询操作
    • 六、封装工具类
      • 6.1、工具类
      • 6.2、工具类使用
  • 02_数据库连接池
    • 一、连接池简介
    • 二、Druid连接池
      • 2.1、准备工作
      • 2.2、Druid连接池使用入门
      • 2.3、封装工具类
        • 2.3.1、使用工具类进行添加操作
        • 2.3.2、使用工具类进行查询操作
    • 三、三层架构
      • 3.1、三层架构是什么
      • 3.2、三层架构项目搭建(按开发步骤)
      • 3.3、案例
  • 03_事务
    • 一、准备工作
    • 二、JDBC中处理事务
      • 2.1、相关方法(必须掌握)
      • 2.2、Dao层处理事务
      • 2.3、Service层才是处理事务的地方
        • 2.3.1、DAO层代码
        • 2.3.2、Service层代码
      • 2.4、修改JdbcUtils
        • 2.4.1、JdbcUtils代码
      • 2.5、JdbcUtils完善(必须掌握)
  • 04_Commons_DbUtils
    • 一、简介
    • 二、主要类及方法
      • 2.1、关于增删改
      • 2.2、关于查询
        • 2.2.1、ResultSetHandler接口
    • 三、使用
      • 3.1、建库建表
      • 3.2、项目搭建
      • 3.3、创建实体类
      • 3.4、DbUtils使用
      • 3.5、事务
        • 3.5.1、DAO代码
        • 3.5.2、Service代码
        • 3.5.3、测试代码

01_JDBC 一、概述 1.1、什么是JDBC

JDBC(Java Database Connectivity,Java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问。

简单说就是用Java语言来操作数据库。原来我们操作数据库是在控制台使用SQL语句来操作数据库,JDBC是用Java语言向数据库发送SQL语句。

1.2、JDBC原理

早期SUN公司的天才们想编写一套可以连接天下所有数据库的API,但是当他们刚刚开始时就发现这是不可完成的任务,因为各个厂商的数据库服务器差异太大了。后来SUN开始与数据库厂商们讨论,最终得出的结论是,由SUN提供一套访问数据库的规范(就是一组接口),并提供连接数据库的协议标准,然后各个数据库厂商会遵循SUN的规范提供一套访问自己公司的数据库服务器的API实现。SUN提供的规范命名为JDBC,而各个厂商提供的,遵循了JDBC规范的,可以访问自己数据库的API被称之为驱动。

JDBC是接口,而JDBC驱动才是接口的实现,没有驱动无法完成数据库连接!每个数据库厂商都有自己的驱动,用来连接自己公司的数据库。

JDBC – Java官方提供 – 一系列接口 – 规范
驱动 – 数据库厂商提供 – JDBC接口的实现类 – 实现

二、JDBC入门 2.1、准备工作 2.1.1、建库建表
DROp DATAbase IF EXISTS mydbjdbc;

CREATE DATAbase mydbjdbc;
USE mydbjdbc;

CREATE TABLE tb_stu ( 
    sid INT PRIMARY KEY auto_increment, 
    sname VARCHAR (50), 
    sage INT, 
    sgender VARCHAR (10) 
);
INSERT INTO tb_stu(sname, sage, sgender) VALUES('John', 20, "male");
INSERT INTO tb_stu(sname, sage, sgender) VALUES('bob', 20, "male");

CREATE TABLE USER(
    username VARCHAR (20), 
    password VARCHAR (20)
);
INSERT INTO USER VALUES('Peter', '123');
INSERT INTO USER VALUES('John', '123');
2.1.2、新建项目
  1. 新建Java项目;
  2. 在项目下新建lib目录;
  3. 将MySQL驱动jar包拷贝到lib目录下;
  4. 选中lib目录右键Add as Library–单击OK。
2.2、建立连接 2.2.1、准备四大参数
//驱动名
String driverName = "com.mysql.jdbc.Driver";
//连接数据库的url
String url = "jdbc:mysql://localhost:3306/mydbjdbc?useSSL=false";
//用户名
String username = "root";
//密码
String password = "root";
2.2.2、加载驱动
//手动加载字节码文件到JVM中
Class.forName(driverName);
2.2.3、准备SQL语句
//SQL语句
String sql = "INSERT INTO tb_stu(sname, sage, sgender) VALUES('Peter', 20, 'male')";
2.2.4、建立连接
//建立连接
Connection connection = DriverManager.getConnection(url, username, password);

//验证是否成功建立连接
System.out.println(connection);

如果能够正常输出连接信息,说明连接建立成功,这是后续一切操作的基础。

2.2.5、常见问题

java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

原因:项目中没有添加MySQL驱动或驱动的名字写错

java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: YES)

原因:用户名或密码错误

com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown database 'mydbjdbc1'

原因:数据库名称不正确

com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failureThe last packet sent successfully to the server was 0 milliseconds ago

原因:MySQL服务没有启动或网络故障

2.3、获取发送SQL的对象
Statement statement = connection.createStatement();
2.4、执行SQL语句
//使用Statement发送SQL语句,返回受影响的行数
int i = statement.executeUpdate(sql);

增、删、改使用executeUpdate

查询使用executeQuery

2.5、处理结果
if(i == 1) {
    System.out.println("添加成功");
}
2.6、释放资源

遵循先开后关原则,释放所使用到的资源对象。

//释放资源
statement.close();
connection.close();

资源对于系统来说非常重要,而且是有限的,用完之后一定要释放。

2.7、完整代码
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class TestJdbc1 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //驱动名
        String driverName = "com.mysql.jdbc.Driver";
        //连接数据库的url
        String url = "jdbc:mysql://localhost:3306/mydbjdbc?useSSL=false";
        //用户名
        String username = "root";
        //密码
        String password = "root";

        //加载驱动
        Class.forName(driverName);
        //SQL语句
        String sql = "INSERT INTO tb_stu(sname, sage, sgender) VALUES('Peter', 20, 'male')";
        //建立连接
        Connection connection = DriverManager.getConnection(url, username, password);

        //System.out.println(connection);
        Statement statement = connection.createStatement();
        //发送SQL语句
        int i = statement.executeUpdate(sql);

        //处理结果
        if(i == 1) {
            System.out.println("添加成功");
        }

        //释放资源
        statement.close();
        connection.close();
    }
}

举一反三,我们可以按照上面的套路进行删除、修改操作。

2.8、上面的程序改进

我们在进行添加或其他操作时,SQL语句中的内容是不可能在程序中写死的,在数据库中操作的数据一定是能够变化的。我们对程序进行如下修改,其他部分不变。

//假设用户输入的数据
String name = "zs";
int age = 10;
String gender = "male";

//SQL语句
//String sql = "INSERT INTO tb_stu(sname, sage, sgender) VALUES('Peter', 20, 'male')";
String sql = "INSERT INTO tb_stu(sname, sage, sgender) VALUES('" + name + "', " + age + ", '" + gender + "')";

通过上面的修改,我们就可以通过Java代码向数据库中添加变化的数据而不是在代码中写死。

同理,删除和修改操作也可以按照这样的套路进行操作。

2.9、改进后的完整代码
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class TestJdbc2 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //驱动名
        String driverName = "com.mysql.jdbc.Driver";
        //连接数据库的url
        String url = "jdbc:mysql://localhost:3306/mydbjdbc?useSSL=false";
        //用户名
        String username = "root";
        //密码
        String password = "root";

        //加载驱动
        Class.forName(driverName);

        //假设用户输入的数据
        String name = "zs";
        int age = 10;
        String gender = "male";

        //SQL语句
        //String sql = "INSERT INTO tb_stu(sname, sage, sgender) VALUES('Peter', 20, 'male')";
        String sql = "INSERT INTO tb_stu(sname, sage, sgender) VALUES('" + name + "', " + age + ", '" + gender + "')";
        //建立连接
        Connection connection = DriverManager.getConnection(url, username, password);

        //System.out.println(connection);
        Statement statement = connection.createStatement();
        //发送SQL语句
        int i = statement.executeUpdate(sql);

        //处理结果
        if(i == 1) {
            System.out.println("添加成功");
        }

        //释放资源
        statement.close();
        connection.close();
    }
}
三、查询操作

查询操作和增删改操作在结果处理上有很大区别,我们有必要深入研究一下。

3.1、获取结果集
//假设用户输入的数据
int stuid = 1;

//SQL语句
String sql = "SELECT * FROM tb_stu WHERe sid=" + stuid;
//建立连接
Connection connection = DriverManager.getConnection(url, username, password);

//System.out.println(connection);
Statement statement = connection.createStatement();
//发送SQL语句,获取结果集
ResultSet resultSet = statement.executeQuery(sql);

查询使用executeQuery

3.2、处理结果集

ResultSet 以表(table)结构进行临时结果的存储,需要通过JDBC API将其中数据进行依次获取。

  • 数据行指针:初始位置在第一行数据前,每调用一次boolean next()方法ResultSet的指针向下移动一行,结果为 true,表示当前行有数据;
  • resultSet.getXxx(整数):代表根据列的编号顺序获得,从1开始(一定要注意);
  • resultSet.getXxx("列名"):代表根据列名获得。
int getInt(int columnIndex) throws SQLException        //获得当前行第N列的int值
int getInt(String columnLabel) throws SQLException    //获得当前行columnLabel列的int值

double getDouble(int columnIndex) throws SQLException        //获得当前行第N列的double值
double getDouble(String columnLabel) throws SQLException    //获得当前行columnLabel列的double值

String getString(int columnIndex) throws SQLException         //获得当前行第N列的String值
String getString(String columnLabel) throws SQLException    //获得当前行columnLabel列的String值

//处理结果
while(resultSet.next()) {
    int id  = resultSet.getInt("sid");
    String sname = resultSet.getString("sname");
    int sage = resultSet.getInt("sage");
    String sgender = resultSet.getString("sgender");
    System.out.println(id);
    System.out.println(sname);
    System.out.println(sage);
    System.out.println(sgender);
}
3.3、查询操作完整代码
import java.sql.*;

public class TestJdbc3 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //驱动名
        String driverName = "com.mysql.jdbc.Driver";
        //连接数据库的url
        String url = "jdbc:mysql://localhost:3306/mydbjdbc?useSSL=false";
        //用户名
        String username = "root";
        //密码
        String password = "root";

        //加载驱动
        Class.forName(driverName);

        //假设用户输入的数据
        int stuid = 1;

        //SQL语句
        String sql = "SELECt * FROM tb_stu WHERe sid=" + stuid;
        //建立连接
        Connection connection = DriverManager.getConnection(url, username, password);

        //System.out.println(connection);
        Statement statement = connection.createStatement();
        //发送SQL语句
        ResultSet resultSet = statement.executeQuery(sql);

        //处理结果
        while(resultSet.next()) {
            int id  = resultSet.getInt("sid");
            String sname = resultSet.getString("sname");
            int sage = resultSet.getInt("sage");
            String sgender = resultSet.getString("sgender");
            System.out.println(id);
            System.out.println(sname);
            System.out.println(sage);
            System.out.println(sgender);
        }

        //释放资源
        resultSet.close();
        statement.close();
        connection.close();
    }
}
四、PreparedStatement 4.1、SQL注入 4.1.1、什么是SQL注入

用户输入的数据中有SQL关键字或语法并且参与了SQL语句的编译,导致SQL语句编译后的条件含义为true,一直得到正确的结果。这种现象称为SQL注入。

4.1.2、SQL注入案例
import java.sql.*;

public class TestJdbc4 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //驱动名
        String driverName = "com.mysql.jdbc.Driver";
        //连接数据库的url
        String url = "jdbc:mysql://localhost:3306/mydbjdbc?useSSL=false";
        //用户名
        String username = "root";
        //密码
        String password = "root";

        //加载驱动
        Class.forName(driverName);

        //假设用户输入的数据
        String n = "abc' OR 1=1 OR '1=1";
        String p = "123";

        //SQL语句
        String sql = "SELECt * FROM user WHERe username='" + n + "' AND password='" + p + "'";
        System.out.println(sql);
        //建立连接
        Connection connection = DriverManager.getConnection(url, username, password);

        //System.out.println(connection);
        Statement statement = connection.createStatement();
        //发送SQL语句
        ResultSet resultSet = statement.executeQuery(sql);

        //处理结果
        while(resultSet.next()) {
            System.out.println(resultSet.getString("username"));
            System.out.println(resultSet.getString("password"));
        }

        //释放资源
        resultSet.close();
        statement.close();
        connection.close();
    }
}
4.1.3、如何避免SQL注入

由于编写的SQL语句是在用户输入数据,整合后再进行编译。所以为了避免SQL注入的问题,我们要使SQL语句在用户输入数据前就已进行编译成完整的SQL语句,再进行填充数据。

使用PreparedStatement。

4.2、PreparedStatement使用

PreparedStatement继承了Statement接口,执行SQL语句的方法无异。

作用:

  • 预编译SQL 语句,效率高。
  • 安全,避免SQL注入 。
  • 可以动态的填充数据,执行多个同构的 SQL 语句。
4.2.1、预编译SQL语句
//SQL语句
String sql = "SELECt * FROM user WHERe username=? AND password=?";

//预编译SQL语句
PreparedStatement statement = connection.prepareStatement(sql);
4.2.2、设置参数
String n = "abc' OR 1=1 OR '1=1";
String p = "123";

//设置参数
statement.setString(1, n);
statement.setString(2, p);
4.2.3、完整代码
import java.sql.*;

public class TestJdbc5 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //驱动名
        String driverName = "com.mysql.jdbc.Driver";
        //连接数据库的url
        String url = "jdbc:mysql://localhost:3306/mydbjdbc?useSSL=false";
        //用户名
        String username = "root";
        //密码
        String password = "root";

        //加载驱动
        Class.forName(driverName);

        //假设用户输入的数据
        String n = "abc' OR 1=1 OR '1=1";
        String p = "123";

        //SQL语句
        String sql = "SELECt * FROM user WHERe username=? AND password=?";
        //建立连接
        Connection connection = DriverManager.getConnection(url, username, password);

        //预编译SQL语句
        PreparedStatement statement = connection.prepareStatement(sql);
        //设置参数
        statement.setString(1, n);
        statement.setString(2, p);

        //发送SQL语句
        ResultSet resultSet = statement.executeQuery();

        //处理结果
        while(resultSet.next()) {
            System.out.println(resultSet.getString("username"));
            System.out.println(resultSet.getString("password"));
        }

        //释放资源
        resultSet.close();
        statement.close();
        connection.close();
    }
}
五、使用JDBC进行CRUD操作(掌握)

在项目实战中,推荐使用PreparedStatement而不是使用Statement。

以下的代码必须熟练掌握,能够举一反三,这是后续学习的基础。

5.1、添加操作
import java.sql.*;

public class TestJdbc6 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //驱动名
        String driverName = "com.mysql.jdbc.Driver";
        //连接数据库的url
        String url = "jdbc:mysql://localhost:3306/mydbjdbc?useSSL=false";
        //用户名
        String username = "root";
        //密码
        String password = "root";

        //加载驱动
        Class.forName(driverName);

        //SQL语句
        String sql = "INSERT INTO tb_stu(sname, sage, sgender) VALUES(?, ?, ?)";
        //建立连接
        Connection connection = DriverManager.getConnection(url, username, password);

        //创建PreparedStatement
        PreparedStatement pstmt = connection.prepareStatement(sql);
        pstmt.setString(1, "zhangsan");
        pstmt.setInt(2, 20);
        pstmt.setString(3, "male");

        //发送SQL语句
        int i = pstmt.executeUpdate();

        //处理结果
        if(i == 1) {
            System.out.println("添加成功");
        }

        //释放资源
        pstmt.close();
        connection.close();
    }
}
5.2、删除操作
import java.sql.*;

public class TestJdbc7 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //驱动名
        String driverName = "com.mysql.jdbc.Driver";
        //连接数据库的url
        String url = "jdbc:mysql://localhost:3306/mydbjdbc?useSSL=false";
        //用户名
        String username = "root";
        //密码
        String password = "root";

        //加载驱动
        Class.forName(driverName);

        //SQL语句
        String sql = "DELETE FROM tb_stu WHERe sid=?";
        //建立连接
        Connection connection = DriverManager.getConnection(url, username, password);

        //创建PreparedStatement
        PreparedStatement pstmt = connection.prepareStatement(sql);
        pstmt.setInt(1, 5);

        //发送SQL语句
        int i = pstmt.executeUpdate();

        //处理结果
        if(i == 1) {
            System.out.println("删除成功");
        }

        //释放资源
        pstmt.close();
        connection.close();
    }
}
5.3、修改操作
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class TestJdbc8 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //驱动名
        String driverName = "com.mysql.jdbc.Driver";
        //连接数据库的url
        String url = "jdbc:mysql://localhost:3306/mydbjdbc?useSSL=false";
        //用户名
        String username = "root";
        //密码
        String password = "root";

        //加载驱动
        Class.forName(driverName);

        //SQL语句
        String sql = "UPDATE tb_stu SET sage=? WHERe sid=?";
        //建立连接
        Connection connection = DriverManager.getConnection(url, username, password);

        //创建PreparedStatement
        PreparedStatement pstmt = connection.prepareStatement(sql);
        pstmt.setInt(1, 25);
        pstmt.setInt(2, 1);

        //发送SQL语句
        int i = pstmt.executeUpdate();

        //处理结果
        if(i == 1) {
            System.out.println("修改成功");
        }

        //释放资源
        pstmt.close();
        connection.close();
    }
}
5.4、查询操作
import java.sql.*;

public class TestJdbc9 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //驱动名
        String driverName = "com.mysql.jdbc.Driver";
        //连接数据库的url
        String url = "jdbc:mysql://localhost:3306/mydbjdbc?useSSL=false";
        //用户名
        String username = "root";
        //密码
        String password = "root";

        //加载驱动
        Class.forName(driverName);

        //SQL语句
        String sql = "SELECT * FROM tb_stu WHERe sgender=?";
        //建立连接
        Connection connection = DriverManager.getConnection(url, username, password);

        //预编译SQL语句
        PreparedStatement statement = connection.prepareStatement(sql);
        //设置参数
        statement.setString(1, "male");

        //发送SQL语句
        ResultSet resultSet = statement.executeQuery();

        //处理结果
        while(resultSet.next()) {
            int sid = resultSet.getInt("sid");
            String sname = resultSet.getString("sname");
            int sage = resultSet.getInt("sage");
            String sgender = resultSet.getString("sgender");
            System.out.println(sid + "---" + sname + "---" + sage + "---" + sgender);
        }

        //释放资源
        resultSet.close();
        statement.close();
        connection.close();
    }
}
六、封装工具类

上面的代码大部分是重复的,我们有必要把重复的代码进行提取。

6.1、工具类
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JdbcUtil {
    //定义成员变量用来保存四大参数
    private static String driverName;
    private static String url;
    private static String username;
    private static String password;

    static {
        try {
            //读取配置文件到输入流
            InputStream in = JdbcUtil.class.getResourceAsStream("/jdbc.properties");
            Properties properties = new Properties();
            //加载配置文件中的数据到Properties中
            properties.load(in);

            //获取四大参数
            driverName = properties.getProperty("jdbc.driverName");
            url = properties.getProperty("jdbc.url");
            username = properties.getProperty("jdbc.username");
            password = properties.getProperty("jdbc.password");

            //加载驱动
            Class.forName(driverName);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    //获取连接
    public static Connection getConnection() {
        Connection connection = null;
        try {
            connection = DriverManager.getConnection(url, username, password);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }

        return connection;
    }

    //释放资源
    public static void close(Connection connection, Statement statement, ResultSet rSet) {
        try {
            if(rSet != null) {
                rSet.close();
            }

            if(statement != null) {
                statement.close();
            }

            if(connection != null) {
                connection.close();
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}
6.2、工具类使用

在src下创建jdbc.properties文件

jdbc.driverName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydbjdbc?useSSL=false
jdbc.username=root
jdbc.password=root

在Java代码中使用工具类

import com.qfedu.utils.JdbcUtil;

import java.sql.*;

public class TestJdbc10 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {

        //SQL语句
        String sql = "SELECt * FROM tb_stu WHERe sgender=?";
        //建立连接 --- 使用工具类
        Connection connection = JdbcUtil.getConnection();
        //预编译SQL语句
        PreparedStatement statement = connection.prepareStatement(sql);
        //设置参数
        statement.setString(1, "male");

        //发送SQL语句
        ResultSet resultSet = statement.executeQuery();

        //处理结果
        while(resultSet.next()) {
            int sid = resultSet.getInt("sid");
            String sname = resultSet.getString("sname");
            int sage = resultSet.getInt("sage");
            String sgender = resultSet.getString("sgender");
            System.out.println(sid + "---" + sname + "---" + sage + "---" + sgender);
        }

        //释放资源 --- 使用工具类
        JdbcUtil.close(connection, statement, resultSet);
    }
}

通过使用工具类,我们的代码变得简洁更容易维护。

02_数据库连接池 一、连接池简介

连接池是一种管理连接的技术。

用连接池来管理Connection,可以重复使用连接。有了连接池,我们就不用自己来创建Connection,而是通过池来获取Connection对象。当使用完Connection后,调用Connection的close()方法也不会真的关闭Connection,而是把Connection归还给池。连接池就可以再利用这个Connection对象了。

Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商可以让自己的连接池实现这个接口。这样应用程序可以方便的切换不同厂商的连接池。

二、Druid连接池

Druid是阿里巴巴开源的一个数据源,主要用于java数据库连接池,相比spring推荐的DBCP和hibernate推荐的C3P0、Proxool数据库连接池,Druid在市场上占有绝对的优势。

2.1、准备工作
  1. 新建Java项目;
  2. 在项目下新建lib目录;
  3. 将MySQL驱动jar包和Druid jar包拷贝到lib目录下;
  4. 选中lib目录右键Add as Library–单击OK。
2.2、Druid连接池使用入门
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;

import java.sql.SQLException;

public class Test1 {
    public static void main(String[] args) throws SQLException {
        //创建Druid连接池对象
        DruidDataSource dataSource = new DruidDataSource();

        //为Druid连接池设置参数
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/mydbjdbc?useSSL=false");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        //初始化连接数量
        dataSource.setInitialSize(10);
        //最大连接数量
        dataSource.setMaxActive(100);
        //最小空闲连接
        dataSource.setMinIdle(5);

        //从连接池中获取连接
        Connection connection = dataSource.getConnection();
        //打印连接
        System.out.println(connection);
        
        //归还连接
        connection.close();
    }
}

通过上面操作我们知道了如何创建连接池,并且获取了连接,有了连接我们就可以进行CRUD操作。

2.3、封装工具类

在实际的开发中,连接池的参数我们不会在Java代码中写死,我们通常将其定义在独立的配置文件中。连接池我们通常放置在工具类中。用户使用的时候直接使用工具类,不直接操作连接池。

在src下创建jdbc.properties文件,内容如下

#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydbjdbc?useSSL=false
username=root
password=root
#初始化连接数量
initialSize=10
#最大连接数量
maxActive=50
#最小空闲连接
minIdle=5

工具类代码如下

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JdbcUtil {
    private static DataSource dataSource;

    static {
        try {
            Properties prop = new Properties();
            //读取配置文件
            InputStream in = JdbcUtil.class.getResourceAsStream("/jdbc.properties");
            prop.load(in);

            //创建DataSource
            dataSource = DruidDataSourceFactory.createDataSource(prop);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //获取连接
    public static Connection getConnection() {
        Connection connection = null;
        try {
            //从连接池获取连接
            connection = dataSource.getConnection();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return connection;
    }

    //释放资源
    public static void close(Connection connection, Statement statement, ResultSet rSet) {
        try {
            if(rSet != null) {
                rSet.close();
            }

            if(statement != null) {
                statement.close();
            }

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

我们已经完成了工具类的编写,接下来我们使用工具类进行CRUD操作。

2.3.1、使用工具类进行添加操作
public class Test2 {
    public static void main(String[] args) throws SQLException {
        String sql = "INSERT INTO tb_stu(sname, sage, sgender) VALUES(?, ?, ?)";

        //获取连接
        Connection connection = JdbcUtil.getConnection();
        //获取PreparedStatement
        PreparedStatement statement = connection.prepareStatement(sql);
        //设置参数
        statement.setString(1, "张三");
        statement.setInt(2, 30);
        statement.setString(3, "male");

        //发送SQL语句
        int i = statement.executeUpdate();
        System.out.println(i);

        //释放资源
        JdbcUtil.close(connection, statement, null);
    }
}

上面的代码,使用工具类完成了添加操作,举一反三,按照相同的套路我们可以完成修改和删除操作。

2.3.2、使用工具类进行查询操作
import com.qfedu.util.JdbcUtil;

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

public class Test3 {
    public static void main(String[] args) throws SQLException {
        //查询名字叫张三的所有学生的信息
        String sql = "SELECT * FROM tb_stu WHERe sname=?";

        //获取连接
        Connection connection = JdbcUtil.getConnection();
        //获取PreparedStatement
        PreparedStatement statement = connection.prepareStatement(sql);
        //设置参数
        statement.setString(1, "张三");

        //发送SQL语句
        ResultSet rset = statement.executeQuery();

        //处理结果
        while(rset.next()) {
            int sid = rset.getInt("sid");
            String sname = rset.getString("sname");
            int sage = rset.getInt("sage");
            String sgender = rset.getString("sgender");
            System.out.println(sid + "---" + sname + "---" + sage + "---" + sgender);
        }

        //释放资源
        JdbcUtil.close(connection, statement, rset);
    }
}
三、三层架构 3.1、三层架构是什么
  • 表示层(View):
    • 命名:XXXView
    • 职责:收集用户的数据和需求、展示数据。
  • 业务逻辑层(Service):
    • 命名:XXXServiceImpl
    • 职责:数据加工处理、调用DAO完成业务实现、控制事务。
  • 数据访问层(Dao):
    • 命名:XXXDaoImpl
    • 职责:向业务层提供数据,将业务层加工后的数据同步到数据库。

3.2、三层架构项目搭建(按开发步骤)
  • utils包存放工具类(JdbcUtils)
  • entity包存放实体类(Telephone)
  • dao包存放Dao接口(TelephoneDao)
    • impl存放DAO接口实现类(TelephoneDaoImpl)
  • service存放Service接口(TelephoneService)
    • impl存放Service接口实现类(TelephoneServiceImpl)
  • view 存放程序启动类(main)

程序设计时,考虑易修改、易扩展,为Service层和DAO层设计接口,便于未来更换实现类

3.3、案例

通讯录,实现对通讯录信息的CRUD操作。

要求,姓名是唯一的,姓名不能重复。

主界面

添加

添加同名信息

查询所有

根据姓名查询

修改通讯录

修改通讯里,修改的名字不存在

修改之后的名字和其他项名字重复,不允许修改

03_事务 一、准备工作

一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。

事务要处理的问题,把多个对数据库的操作绑定成一个事务,要么都成功,要么都失败。

DROp DATAbase if exists mydb2;
CREATE DATAbase mydb2;

USE mydb2;


DROP TABLE IF EXISTS account;
CREATE TABLE account  (
  id int(11) NOT NULL AUTO_INCREMENT,
  cardnum varchar(5) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  money decimal(10, 0) NULL DEFAULT NULL,
  PRIMARY KEY (id) USING BTREE
);

INSERT INTO account VALUES (1, '10001', 5000);
INSERT INTO account VALUES (2, '10002', 5000);
二、JDBC中处理事务

在JDBC中处理事务,都是通过Connection完成的;

同一事务中所有的操作,都在使用同一个Connection对象。

2.1、2.5必须掌握,2.2~2.4了解分析过程就可以。

2.1、相关方法(必须掌握)

以下的方法都是Connection中的方法。

setAutoCommit(boolean)如果true(默认值就是true)表示自动提交,con.setAutoCommit(false)表示开启事务;

commit()提交事务

rollback()回滚事务

JDBC处理事务的代码格式:

try {
  con.setAutoCommit(false);//开启事务…
  //多个JDBC操作
  
  con.commit();//try的最后提交事务
} catch() {
  con.rollback();//回滚事务
}
2.2、Dao层处理事务
public class AccountDao {    
    //转账
    
    
    public void trans(String src, String dst, double money) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        String sql1 = "update account set money=money-? where cardNum=?";
        String sql2 = "update account set money=money+? where cardNum=?";
        try {
            //获取连接
            conn = JdbcUtils.getConnection();
            //开启事务
            conn.setAutoCommit(false);//禁止自动提交
            //转账操作
            //操作1
            pstmt = conn.prepareStatement(sql1);
            //设置参数
            pstmt.setDouble(1, money);
            pstmt.setString(2, src);
            //发送SQL
            pstmt.executeUpdate();

            //用来测试回滚
            //int i = 100/0;

            //操作2
            pstmt = conn.prepareStatement(sql2);
            //设置参数
            pstmt.setDouble(1, money);
            pstmt.setString(2, dst);
            //发送SQL
            pstmt.executeUpdate();

            //提交事务
            conn.commit();
        } catch (Exception e) {
            e.printStackTrace();
            try {
                //回滚事务
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        } finally {
            //释放资源
            JdbcUtils.close(conn, null, null);
        }
    }
}
2.3、Service层才是处理事务的地方

我们要清楚一件事,DAO中不是处理事务的地方,因为DAO中的每个方法都是对数据库的一次操作,而Service中的方法才是对应一个业务逻辑。也就是说我们需要在Service中的一方法中调用DAO的多个方法,而这些方法应该在一个事务中。

DAO层中的方法只进行最细粒度的增删改查;

Service层处理业务,对DAO层的方法进行组合。

怎么才能让DAO的多个方法使用相同的Connection呢?方法不能再自己来获得Connection,而是由外界传递进去。

public void daoMethod1(Connection con, …) {//操作1 减去xx
}

public void daoMethod2(Connection con, …) {//操作2 加上xx
}
2.3.1、DAO层代码
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class AccountDao {  
  
    public void withdrawal(Connection conn, String cardNum, double money) throws SQLException {
        String sql = "update account set money=money-? where cardNum=?";
        PreparedStatement pstmt = null;

        //操作
        pstmt = conn.prepareStatement(sql);
        //设置参数
        pstmt.setDouble(1, money);
        pstmt.setString(2, cardNum);
        //发送SQL
        pstmt.executeUpdate();

        pstmt.close();
    }

    
    public void deposit(Connection conn, String cardNum, double money) throws SQLException {
        String sql = "update account set money=money+? where cardNum=?";

        PreparedStatement pstmt = null;

        //操作
        pstmt = conn.prepareStatement(sql);
        //设置参数
        pstmt.setDouble(1, money);
        pstmt.setString(2, cardNum);
        //发送SQL
        pstmt.executeUpdate();

        pstmt.close();
    }
}
2.3.2、Service层代码
import com.qfedu.dao.AccountDao;
import com.qfedu.utils.JdbcUtils;

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

public class AccountService {
    private AccountDao accountDao = new AccountDao();
    //转账操作
    public void trans(String src, String dst, double money) {
        Connection connection = null;

        try {
            //获取连接
            connection = JdbcUtils.getConnection();
            //开启事务
            connection.setAutoCommit(false);
            //提款
            accountDao.withdrawal(connection, src, money);
            
            //用来测试回滚
            int i = 100/0;
            
            //存款
            accountDao.deposit(connection, dst, money);
            //提交事务
            connection.commit();
        } catch (Exception e) { //注意这里异常的类型
            e.printStackTrace();
            try {
                //回滚
                connection.rollback();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        } finally {
            //释放资源
            JdbcUtils.close(connection, null, null);
        }
    }
}

在Service中不应该出现Connection,它应该只在DAO中出现,因为它是JDBC的东西,JDBC的东西是用来连接数据库的,连接数据库是DAO的事情,但是,事务是Service的事儿,不能放到DAO中。

2.4、修改JdbcUtils

我们把对事务的开启和关闭放到JdbcUtils中,在Service中调用JdbcUtils的方法来完成事务的处理,但在Service中就不会再出现Connection这一“禁忌”了。

DAO中的方法不用再让Service来传递Connection了。DAO会主动从JdbcUtils中获取Connection对象,这样,JdbcUtils成为了DAO和Service的中介!

我们在JdbcUtils中添加beginTransaction()和rollbackTransaction(),以及commitTransaction()方法。这样在Service中的代码如下

public class XXXService() {
   private XXXDao dao = new XXXDao();
   public void serviceMethod() {
       try {
          JdbcUtils.beginTransaction();//开启事务
          dao.daoMethod1(…);//操作1
          dao.daoMethod2(…); //操作2
          JdbcUtils.commitTransaction();//提交事务
        } catch(Exception e) {
           JdbcUtils.rollbackTransaction();//回滚
        }
    }
}

要保证两个方法中获取的conn是同一个

DAO代码如下

public void daoMethod1(…) {
    Connection con = JdbcUtils.getConnection();
}

public void daoMethod2(…) {
    Connection con = JdbcUtils.getConnection();
}

在Service层方法中调用了JdbcUtil.beginTransaction()方法后,JdbcUtil要做准备好一个已经调用了setAuthCommitted(false)方法的Connection对象,因为在Service中调用JdbcUtils.beginTransaction()之后,马上就会调用DAO的方法,而在DAO方法中会调用JdbcUtils.getConnection()方法。这说明JdbcUtils要在getConnection()方法中返回刚刚准备好的,已经设置了手动提交的Connection对象。

在JdbcUtils中创建一个Connection con属性,当它为null时,说明没有事务!当它不为null时,表示开启了事务。

  • 在没有开启事务时,可以调用“开启事务”方法;
  • 在开启事务后,可以调用“提交事务”和“回滚事务”方法;
  • getConnection()方法会在con不为null时返回con,在con为null时,从连接池中返回连接。

beginTransaction()

  • 判断con是否为null,如果不为null,就抛出异常!
  • 如果con为null,那么从连接池中获取一个Connection对象,赋值给con!然后设置它为“手动提交”。

getConnection()

  • 判断con是否为null,如果为null说明没有事务,那么从连接池获取一个连接返回;
  • 如果不为null,说明已经开始了事务,那么返回con属性返回。这说明在con不为null时,无论调用多少次getConnection()方法,返回的都是同个Connection对象。

commitTransaction()

  • 判断con是否为null,如果为null,说明没有开启事务就提交事务,那么抛出异常;
  • 如果con不为null,那么调用con的commit()方法来提交事务;
  • 调用con.close()方法关闭连接;
  • con = null,这表示事务已经结束!

rollbackTransaction()

  • 判断con是否为null,如果为null,说明没有开启事务就回滚事务,那么抛出异常;
  • 如果con不为null,那么调用con的rollback()方法来回滚事务;
  • 调用con.close()方法关闭连接;
  • con = null,这表示事务已经结束!
2.4.1、JdbcUtils代码
package com.qfedu.utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JdbcUtils {
    private static DataSource dataSource;
    private static Connection connection;

    static {
        try {
            Properties prop = new Properties();
            InputStream in = JdbcUtils.class.getResourceAsStream("/jdbc.properties");
            prop.load(in);

            //创建DataSource
            dataSource = DruidDataSourceFactory.createDataSource(prop);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //获取连接
    public static Connection getConnection() throws SQLException {
        if(connection != null) {
            return connection;
        }
        return dataSource.getConnection();
    }

    //开启事务
    public static void beginTransaction() throws SQLException {
        if(connection != null) {
            throw new SQLException("事务已经开启,在没有结束当前事务时,不能再开启事务!");
        }

        connection = dataSource.getConnection();
        connection.setAutoCommit(false);
    }

    //提交事务
    public static void commitTransaction() throws SQLException {
        if(connection == null) {
            throw new SQLException("当前没有事务,所以不能提交事务!");
        }

        connection.commit();
        connection.close();
        connection = null;
    }

    //回滚事务
     public static void rollbackTransaction() throws SQLException {
        if(connection == null) {
            throw new SQLException("当前没有事务,所以不能回滚事务!");
        }

        connection.rollback();
        connection.close();
        connection = null;
     }

    //释放资源
    public static void close(Connection connection, Statement statement, ResultSet rSet) {
        try {
            if(rSet != null) {
                rSet.close();
            }

            if(statement != null) {
                statement.close();
            }

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

2.4.2、DAO代码

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class AccountDao {  
    
    public void withdrawal(String cardNum, double money) throws SQLException {
        String sql = "update account set money=money-? where cardNum=?";
        PreparedStatement pstmt = null;

        Connection conn = JdbcUtils.getConnection();
        //操作
        pstmt = conn.prepareStatement(sql);
        //设置参数
        pstmt.setDouble(1, money);
        pstmt.setString(2, cardNum);
        //发送SQL
        pstmt.executeUpdate();

        pstmt.close();
    }

    
    public void deposit(String cardNum, double money) throws SQLException {
        String sql = "update account set money=money+? where cardNum=?";

        PreparedStatement pstmt = null;

        Connection conn = JdbcUtils.getConnection();
        //操作
        pstmt = conn.prepareStatement(sql);
        //设置参数
        pstmt.setDouble(1, money);
        pstmt.setString(2, cardNum);
        //发送SQL
        pstmt.executeUpdate();

        pstmt.close();
    }
}

2.4.3、Service代码

import com.qfedu.dao.AccountDao;
import com.qfedu.utils.JdbcUtils;

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

public class AccountService {
    private AccountDao accountDao = new AccountDao();
    //转账操作
    public void trans(String src, String dst, double money) {

        try {
            //开启事务
            JdbcUtils.beginTransaction();
            //取款
            accountDao.withdrawal(src, money);
            
            //用来测试回滚
            //int i = 100/0;
            //存款
            accountDao.deposit(dst, money);
            //提交事务
            JdbcUtils.commitTransaction();
        } catch (Exception e) { //注意这里异常的类型
            e.printStackTrace();
            try {
                //回滚
                JdbcUtils.rollbackTransaction();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}
2.5、JdbcUtils完善(必须掌握)

现在JdbcUtils有个问题,如果有两个线程!第一个线程调用了beginTransaction()方法,另一个线程再调用beginTransaction()方法时,因为con已经不再为null,所以就会抛出异常了。

我们希望JdbcUtils可以多线程环境下被使用!最好的方法是为每个线程提供一个Connection,这样每个线程都可以开启自己的事务了。

ThreadLocal类只有三个方法:

  • void set(T value):保存值;
  • T get():获取值;
  • void remove():移除值。

ThreadLocal内部其实是个Map来保存数据。虽然在使用ThreadLocal时只给出了值,没有给出键,其实它内部使用了当前线程做为键。

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JdbcUtils {
    private static DataSource dataSource;
    private static ThreadLocal tl = new ThreadLocal();

    static {
        try {
            Properties prop = new Properties();
            InputStream in = JdbcUtils.class.getResourceAsStream("/jdbc.properties");
            prop.load(in);

            //创建DataSource
            dataSource = DruidDataSourceFactory.createDataSource(prop);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //获取连接
    public static Connection getConnection() throws SQLException {
        Connection connection = tl.get();

        if(connection != null) {
            return connection;
        }
        return dataSource.getConnection();
    }

    //开启事务
    public static void beginTransaction() throws SQLException {
        Connection connection = tl.get();
        if(connection != null) {
            throw new SQLException("事务已经开启,在没有结束当前事务时,不能再开启事务!");
        }

        connection = dataSource.getConnection();
        connection.setAutoCommit(false);
        tl.set(connection);
    }

    //提交事务
    public static void commitTransaction() throws SQLException {
        Connection connection = tl.get();
        if(connection == null) {
            throw new SQLException("当前没有事务,所以不能提交事务!");
        }

        connection.commit();
        connection.close();
        tl.remove();
    }

    //回滚事务
     public static void rollbackTransaction() throws SQLException {
        Connection connection = tl.get();
        if(connection == null) {
            throw new SQLException("当前没有事务,所以不能回滚事务!");
        }

        connection.rollback();
        connection.close();
        tl.remove();
     }

    //释放资源
    public static void close(Connection connection, Statement statement, ResultSet rSet) {
        try {
            if(rSet != null) {
                rSet.close();
            }

            if(statement != null) {
                statement.close();
            }

            if(connection != null) {
                connection.close();
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}
04_Commons_DbUtils 一、简介

DBUtils是Apache Commons组件中的一员,开源免费。是对JDBC的简单封装,但是它还是被很多公司使用。

主要功能:用来操作数据库,简化JDBC的操作。

在使用的时候要和数据库连接池、MySQL的jar包配合使用。

二、主要类及方法

**QueryRunner:**执行sql语句的类

  • 创建QueryRunner

    • 构造器:QueryRunner() ,在事务里面使用;
    • 构造器:QueryRunner(连接池对象)
  • update():执行INSERT、UPDATE、DELETE

  • query():执行SELECT

2.1、关于增删改

int update(String sql, Object… params) --> 可执行增、删、改语句

int update(Connection con, String sql, Object… parmas) --> 需要调用者提供Connection,支持事务

2.2、关于查询

T query(String sql, ResultSetHandler rsh, Object… params) --> 可执行查询

T query(Connection con, String sql, ResultSetHadler rsh, Object… params) --> 需要调用者提供Connection,支持事务

2.2.1、ResultSetHandler接口

BeanHandler(单行) --> 构造器需要一个Class类型的参数,用来把一行结果转换成指定类型的javaBean对象;

BeanListHandler(多行) --> 构造器也是需要一个Class类型的参数,用来把一行结果集转换成一个javabean,那么多行就是转换成List对象,一堆javabean;

MapHandler(单行) --> 把一行结果集转换Map对象;

MapListHandler(多行) --> 把一行记录转换成一个Map,多行就是多个Map,即List;

ScalarHandler(单行单列) --> 通常用与select count(*) from t_stu语句!结果集是单行单列的!它返回一个Object 聚合函数。

三、使用 3.1、建库建表
DROp DATAbase IF EXISTS mydbutils;

CREATE DATAbase mydbutils;
USE mydbutils;

CREATE TABLE tb_stu ( 
    sid INT PRIMARY KEY auto_increment, 
    sname VARCHAR (50), 
    sage INT, 
    sgender VARCHAR (10) 
);
INSERT INTO tb_stu(sname, sage, sgender) VALUES('John', 20, "male");
INSERT INTO tb_stu(sname, sage, sgender) VALUES('bob', 20, "male");

CREATE TABLE USER(
    username VARCHAR (20), 
    password VARCHAR (20)
);
INSERT INTO USER VALUES('Peter', '123');
INSERT INTO USER VALUES('John', '123');

CREATE TABLE account  (
  id int(11) NOT NULL AUTO_INCREMENT,
  cardnum varchar(5) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  money decimal(10, 0) NULL DEFAULT NULL,
  PRIMARY KEY (id) USING BTREE
);
INSERT INTO account VALUES (1, '10001', 5000);
INSERT INTO account VALUES (2, '10002', 5000);
3.2、项目搭建
  1. 新建Java项目;
  2. 在项目下新建lib目录;
  3. 将MySQL驱动Jar包、Druid连接池Jar包、DbUtils的Jar包拷贝到lib目录下;
  4. 选中lib目录右键Add as Library–单击OK;
  5. 将之前使用的最新版本的JdbcUtils工具类拷贝到项目中,并增加如下的方法。
//获取连接池对象
public static DataSource getDataSource() {
    return dataSource;
}
3.3、创建实体类
public class Student {
    private int sid;
    private String sname;
    private int sage;
    private String sgender;
    
    //get、set
    //toString...
}
3.4、DbUtils使用
import com.qfedu.entity.Student;
import com.qfedu.utils.JdbcUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.junit.Test;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.List;

public class MyTest {
    private DataSource dataSource = JdbcUtils.getDataSource();

    //测试添加
    @Test
    public void testAdd() {
        //创建QueryRunner
        QueryRunner qr = new QueryRunner(dataSource);
        //SQL
        String sql = "INSERT INTO tb_stu(sname, sage, sgender) VALUES(?, ?, ?)";
        int result = 0;
        //参数
        Object[] params = {"zhangsan", 12, "male"};
        //操作--增
        try {
            result = qr.update(sql, params);
            System.out.println(result);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    //测试删除
    @Test
    public void testDel() {
        QueryRunner qr = new QueryRunner(dataSource);

        String sql = "DELETE FROM tb_stu WHERe sid=?";
        int result = 0;

        Object[] params = {5};

        try {
            result = qr.update(sql, params);
            System.out.println(result);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    //测试修改
    @Test
    public void testUpdate() {
        QueryRunner qr = new QueryRunner(dataSource);

        String sql = "UPDATE tb_stu SET sname=? WHERe sid=?";
        int result = 0;

        Object[] params = {"zs", 1};

        try {
            result = qr.update(sql, params);
            System.out.println(result);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    //测试查询
    @Test
    public void testSelect1() {
        QueryRunner qr = new QueryRunner(dataSource);
        String sql = "SELECT * FROM tb_stu WHERe sid=?";
        Student stu = null;
        Object[] params = {1};
        try {
            stu = qr.query(sql, new BeanHandler(Student.class), params);
            System.out.println(stu);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    //测试查询
    @Test
    public void testSelect2() {
        QueryRunner qr = new QueryRunner(dataSource);
        String sql = "SELECT * FROM tb_stu";
        List list = null;
        try {
            list =  qr.query(sql, new BeanListHandler(Student.class));
            for (Student student : list) {
                System.out.println(student);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    //测试查询
    @Test
    public void testSelect3() {
        QueryRunner qr = new QueryRunner(dataSource);
        String sql = "SELECT count(*) FROM tb_stu";

        long count = 0;

        try {
            count = qr.query(sql, new ScalarHandler());
            System.out.println(count);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
3.5、事务

以下代码基于03_事务2.4.2、2.4.3的代码

3.5.1、DAO代码
import com.qfedu.utils.JdbcUtils;
import org.apache.commons.dbutils.QueryRunner;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class AccountDao {
    
    public void withdrawal(String cardNum, double money) throws SQLException {
        String sql = "update account set money=money-? where cardNum=?";

        Object[] params = {money, cardNum};

        QueryRunner qr = new QueryRunner();
        qr.update(JdbcUtils.getConnection(), sql, params);
    }

    
    public void deposit(String cardNum, double money) throws SQLException {
        String sql = "update account set money=money+? where cardNum=?";

        Object[] params = {money, cardNum};

        QueryRunner qr = new QueryRunner();
        qr.update(JdbcUtils.getConnection(), sql, params);
    }
}
3.5.2、Service代码
import com.qfedu.dao.AccountDao;
import com.qfedu.utils.JdbcUtils;

import java.sql.SQLException;

public class AccountService {
    private AccountDao accountDao = new AccountDao();

    //转账操作
    public void trans(String src, String dst, double money) {

        try {
            JdbcUtils.beginTransaction();
            accountDao.withdrawal(src, money);

            //int i = 100/0;

            accountDao.deposit(dst, money);
            JdbcUtils.commitTransaction();
        } catch (Exception e) {
            e.printStackTrace();
            try {
                JdbcUtils.rollbackTransaction();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}
3.5.3、测试代码
@Test
public void testTransaction() {
    AccountService accountService = new AccountService();

    accountService.trans("10001", "10002", 1000);
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/299436.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号