JDBC、数据库连接池、JDBCTemplate

概述:本文记录了JDBC (Java DataBase Connectivity) 的相关知识,JDBC的基本概念级用法,数据库的连接池和JDBCTemplate。

JDBC

JDBC的基本概念

概念

Java DataBase Connectivity 是Java数据库连接, Java语言操作数据库

JDBC本质:其实是官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口

各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。

完整的连接步骤:

步骤:

(注意检查JDK的版本是否对应,另外注意executeUpdate只能用于操作Update语句,不能用于Select等语句)

  1. 导入驱动jar包 如mysql-connector-java-8.0.13.jar(mysql8.0之前的要用另外的版本)
    (1)复制jar包到项目的libs目录下
    (2)右键–>Add As Library

  2. 注册驱动

  3. 获取数据库连接对象 Connection

    (注意账号密码对应,数据库名字对应,设置useSSL和serverTimezone)

  4. 定义sql

  5. 获取执行sql语句的对象 Statement

  6. 执行sql,接受返回结果

  7. 处理结果

  8. 释放资源

    代码实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.Statement;

    /**
    * JDBC快速入门
    */
    public class JdbcDemo1 {
    public static void main(String[] args) throws Exception {
    //1. 导入驱动jar包
    //2.注册驱动 mysql 5 之后注册驱动可以省略
    Class.forName("com.mysql.cj.jdbc.Driver");
    //3.获取数据库连接对象
    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode?useSSL=false&serverTimezone=GMT%2B8", "root", "123456");
    //4.定义sql语句
    String sql = "update t_user set name = 'abc' where id = 2;";
    //5.获取执行sql的对象 Statement
    Statement stmt = conn.createStatement();
    //6.执行sql
    int count = stmt.executeUpdate(sql);
    //7.处理结果
    System.out.println(count);
    //8.释放资源
    stmt.close();
    conn.close();
    }
    }

详解各个对象

DriverManager:驱动管理对象

功能:

  1. 注册驱动:告诉程序该使用哪一个数据库驱动jar
    static void registerDriver(Driver driver) : 注册与给定的驱动程序 DriverManager 。
1
2
3
4
5
6
7
8
9
//写代码使用:  Class.forName("com.mysql.cj.jdbc.Driver");
//通过查看源码发现:在com.mysql.cj.jdbc.Driver类中存在静态代码块
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}

注意:mysql5之后的驱动jar包可以省略注册驱动的步骤。

  1. 获取数据库连接:
  • 方法:static Connection getConnection(String url, String user, String password)

  • 参数:

    • url:指定连接的路径
      * 语法:jdbc:mysql://ip地址(域名):端口号/数据库名称
      * 例子:jdbc:mysql://localhost:3306/db3
      * 细节:如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称

    • user:用户名

    • password:密码

Connection:数据库连接对象

功能:

  1. 获取执行sql 的对象
    • Statement createStatement()
    • PreparedStatement prepareStatement(String sql)
  2. 管理事务:
    • 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
    • 提交事务:commit()
    • 回滚事务:rollback()
Statement:执行sql的对象

执行sql

  • boolean execute(String sql) :可以执行任意的sql

  • int executeUpdate(String sql) :执行DML(insert、update、delete)语句、DDL(create,alter、drop)语句

    返回值:影响的行数,可以通过这个影响的行数判断DML语句是否执行成功 返回值>0的则执行成功,反之,则失败。

  • ResultSet executeQuery(String sql) :执行DQL(select)语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

/**
* 以插入操作为例,更加标准的代码,包括异常的处理
*/
public class JDBCDemo2 {
public static void main(String[] args) {
Statement stmt = null;
Connection conn = null;
try {
//1. 注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2. 定义sql
String sql = "insert into t_user(id,name,birth) values(2, '章齐', '1998-05-28');\n";
//3.获取Connection对象
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode?useSSL=false&serverTimezone=GMT%2B8", "root", "123456");
//4.获取执行sql的对象 Statement
stmt = conn.createStatement();
//5.执行sql
int count = stmt.executeUpdate(sql);//影响的行数
//6.处理结果
System.out.println(count);
if(count > 0){
System.out.println("添加成功!");
}else{
System.out.println("添加失败!");
}

} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//stmt.close();
//7. 释放资源
//避免空指针异常
if(stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
ResultSet:结果集对象,封装查询结果
  • boolean next(): 游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),如果是,则返回false,如果不是则返回true
  • getXxx(参数):获取数据
    • Xxx:代表数据类型 如: int getInt() , String getString()
    • 参数:
      1. int:代表列的编号,从1开始 如: getString(1)
      2. String:代表列名称。 如: getDouble(“balance”)
PreparedStatement:执行sql的对象
  1. SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题
    1. 输入用户随便,输入密码:a’ or ‘a’ = ‘a
    2. sql:select * from user where username = ‘fhdsjkf’ and password = ‘a’ or ‘a’ = ‘a’
  2. 解决sql注入问题:使用PreparedStatement对象来解决
  3. 预编译的SQL:参数使用?作为占位符
  4. 步骤:
    1. 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
    2. 注册驱动
    3. 获取数据库连接对象 Connection
    4. 定义sql
      • 注意:sql的参数使用?作为占位符。 如:select * from user where username = ? and password = ?;
    5. 获取执行sql语句的对象 PreparedStatement Connection.prepareStatement(String sql)
    6. 给?赋值:
      • 方法: setXxx(参数1,参数2)
        • 参数1:?的位置编号 从1 开始
        • 参数2:?的值
    7. 执行sql,接受返回结果,不需要传递sql语句
    8. 处理结果
    9. 释放资源
  5. 注意:后期都会使用PreparedStatement来完成增删改查的所有操作
    1. 可以防止SQL注入
    2. 效率更高
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import cn.itcast.util.JDBCUtils;

import java.sql.*;
import java.util.Scanner;

/**
* * 需求:
* 1. 通过键盘录入用户名和密码
* 2. 判断用户是否登录成功
*/
public class JDBCDemo9 {

public static void main(String[] args) {
//1.键盘录入,接受用户名和密码
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名:");
String username = sc.nextLine();
System.out.println("请输入密码:");
String password = sc.nextLine();
//2.调用方法
boolean flag = new JDBCDemo9().login2(username, password);
//3.判断结果,输出不同语句
if(flag){
//登录成功
System.out.println("登录成功!");
}else{
System.out.println("用户名或密码错误!");
}
}


/**
* 登录方法,存在SQL注入的问题
*/
public boolean login(String username ,String password){
if(username == null || password == null){
return false;
}
//连接数据库判断是否登录成功
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
//1.获取连接
try {
conn = JDBCUtils.getConnection();
//2.定义sql
String sql = "select * from user where username = '"+username+"' and password = '"+password+"' ";
System.out.println(sql);
//3.获取执行sql的对象
stmt = conn.createStatement();
//4.执行查询
rs = stmt.executeQuery(sql);
//5.判断
return rs.next();//如果有下一行,则返回true

} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtils.close(rs,stmt,conn);
}


return false;
}

/**
* 登录方法,使用PreparedStatement实现
*/
public boolean login2(String username ,String password){
if(username == null || password == null){
return false;
}
//连接数据库判断是否登录成功
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
//1.获取连接
try {
conn = JDBCUtils.getConnection();
//2.定义sql
String sql = "select * from user where username = ? and password = ?";
//3.获取执行sql的对象
pstmt = conn.prepareStatement(sql);
//4.给?赋值
pstmt.setString(1,username);
pstmt.setString(2,password);
//5.执行查询,不需要传递sql
rs = pstmt.executeQuery();
//6.判断
return rs.next();//如果有下一行,则返回true

} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtils.close(rs,pstmt,conn);
}
return false;
}
}

抽取JDBC工具类 : JDBCUtils

  • 目的:简化书写(减少重复书写的代码)
  • 分析:
    1. 注册驱动也抽取

    2. 抽取一个方法获取连接对象

      • 需求:不想传递参数(麻烦),还得保证工具类的通用性。
      • 解决:配置文件
        jdbc.properties
        url=
        user=
        password=
    3. 抽取一个方法释放资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;

/**
* JDBC工具类
*/
public class JDBCUtils {
private static String url;
private static String user;
private static String password;
private static String driver;
/**
* 文件的读取,只需要读取一次即可拿到这些值。使用静态代码块
*/
static{
//读取资源文件,获取值。

try {
//1. 创建Properties集合类。
Properties pro = new Properties();

//获取src路径下的文件的方式--->ClassLoader 类加载器
ClassLoader classLoader = JDBCUtils.class.getClassLoader();
URL res = classLoader.getResource("jdbc.properties");
String path = res.getPath();
// System.out.println(path);///D:/IdeaProjects/itcast/out/production/day04_jdbc/jdbc.properties
//2. 加载文件
// pro.load(new FileReader("D:\\IdeaProjects\\itcast\\day04_jdbc\\src\\jdbc.properties"));
pro.load(new FileReader(path));

//3. 获取数据,赋值
url = pro.getProperty("url");
user = pro.getProperty("user");
password = pro.getProperty("password");
driver = pro.getProperty("driver");
//4. 注册驱动
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}


/**
* 获取连接
* @return 连接对象
*/
public static Connection getConnection() throws SQLException {

return DriverManager.getConnection(url, user, password);
}

/**
* 释放资源
* @param stmt
* @param conn
*/
public static void close(Statement stmt,Connection conn){
if( stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}

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


/**
* 释放资源
* @param stmt
* @param conn
*/
public static void close(ResultSet rs,Statement stmt, Connection conn){
if( rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}

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

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

}

JDBC控制事务

  1. 事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
  2. 操作:
    1. 开启事务
    2. 提交事务
    3. 回滚事务
  3. 使用Connection对象来管理事务
    • 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
      • 在执行sql之前开启事务
    • 提交事务:commit()
      • 当所有sql都执行完提交事务
    • 回滚事务:rollback()
      • 在catch中回滚事务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import cn.itcast.util.JDBCUtils;

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

/**
* 事务操作
*/
public class JDBCDemo10 {

public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt1 = null;
PreparedStatement pstmt2 = null;

try {
//1.获取连接
conn = JDBCUtils.getConnection();
//开启事务
conn.setAutoCommit(false);

//2.定义sql
//2.1 张三 - 500
String sql1 = "update account set balance = balance - ? where id = ?";
//2.2 李四 + 500
String sql2 = "update account set balance = balance + ? where id = ?";
//3.获取执行sql对象
pstmt1 = conn.prepareStatement(sql1);
pstmt2 = conn.prepareStatement(sql2);
//4. 设置参数
pstmt1.setDouble(1,500);
pstmt1.setInt(2,1);

pstmt2.setDouble(1,500);
pstmt2.setInt(2,2);
//5.执行sql
pstmt1.executeUpdate();
// 手动制造异常
int i = 3/0;

pstmt2.executeUpdate();
//如果没有一场发生,则提交事务
conn.commit();
} catch (Exception e) {
//事务回滚
try {
if(conn != null) {
conn.rollback();
}
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally {
JDBCUtils.close(pstmt1,conn);
JDBCUtils.close(pstmt2,null);
}
}
}

数据库连接池

  1. 概念:其实就是一个容器(集合),存放数据库连接的容器。
    当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,(不会将连接释放掉)会将连接对象归还给容器。

  2. 好处:

    • 节约资源

    • 用户访问高效(避免了多次向底层申请资源(连接对象))

  3. 实现:

    标准接口:DataSource javax.sql包下的

    方法

    • 获取连接:getConnection()
    • 归还连接:Connection.close()。如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了。而是归还连接

    一般我们不去实现它,由数据库厂商来实现

    • C3P0:数据库连接池技术

    • Druid:数据库连接池实现技术,由阿里巴巴提供的

  4. C3P0:数据库连接池技术

    步骤:

    1. 导入jar包 (两个) c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar ,

      • 不要忘记导入数据库驱动jar包
    2. 定义配置文件:

      • 名称: c3p0.properties 或者 c3p0-config.xml
      • 路径:直接将文件放在src目录下即可。
    3. 创建核心对象 数据库连接池对象 ComboPooledDataSource

    4. 获取连接: getConnection

    • 代码:
    1
    2
    3
    4
    //1.创建数据库连接池对象
    DataSource ds = new ComboPooledDataSource();
    //2. 获取连接对象
    Connection conn = ds.getConnection();

    注意xml文件配置(特别注意在 jdbcUrl 转义&的写法(&amp))

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    <c3p0-config>
    <!-- 使用默认的配置读取连接池对象 -->
    <default-config>
    <!-- 连接参数 -->
    <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/bjpowernode?useSSL=false&amp;serverTimezone=GMT%2B8</property>
    <property name="user">root</property>
    <property name="password">123456</property>

    <!-- 连接池参数 -->
    <!--初始化申请的连接数量-->
    <property name="initialPoolSize">5</property>
    <!--最大的连接数量-->
    <property name="maxPoolSize">10</property>
    <!--超时时间-->
    <property name="checkoutTimeout">3000</property>
    </default-config>

    <named-config name="otherc3p0">
    <!-- 连接参数 -->
    <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/bjpowernode?useSSL=false</property>
    <property name="user">root</property>
    <property name="password">123456</property>

    <!-- 连接池参数 -->
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">8</property>
    <property name="checkoutTimeout">1000</property>
    </named-config>
    </c3p0-config>
  5. Druid:数据库连接池实现技术,由阿里巴巴提供的

    1. 步骤:
      1. 导入jar包 druid-1.0.9.jar
      2. 定义配置文件:
        • 是properties形式的
        • 可以叫任意名称,可以放在任意目录下
      3. 加载配置文件。Properties
      4. 获取数据库连接池对象:通过工厂来来获取 DruidDataSourceFactory
      5. 获取连接:getConnection
    • 代码:
    1
    2
    3
    4
    5
    6
    7
    8
      //3.加载配置文件
    Properties pro = new Properties();
    InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
    pro.load(is);
    //4.获取连接池对象
    DataSource ds = DruidDataSourceFactory.createDataSource(pro);
    //5.获取连接
    Connection conn = ds.getConnection();
    1
    2
    3
    4
    5
    6
    7
    driverClassName=com.mysql.cj.jdbc.Driver
    url=jdbc:mysql://localhost:3306/bjpowernode?useSSL=false&serverTimezone=GMT%2B8
    username=root
    password=123456
    initialSize=5
    maxActive=10
    maxWait=3000
    1. 定义工具类
      1. 定义一个类 JDBCUtils

      2. 提供静态代码块加载配置文件,初始化连接池对象

      3. 提供方法

        • 获取连接方法:通过数据库连接池获取连接

        • 释放资源

        • 获取连接池的方法

  • 代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    /**
    * Druid连接池的工具类
    */
    public class JDBCUtils {
    //1.定义成员变量 DataSource
    private static DataSource ds ;

    static{
    try {
    //1.加载配置文件
    Properties pro = new Properties();
    pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
    //2.获取DataSource
    ds = DruidDataSourceFactory.createDataSource(pro);
    } catch (IOException e) {
    e.printStackTrace();
    } catch (Exception e) {
    e.printStackTrace();
    }
    }

    /**
    * 获取连接
    */
    public static Connection getConnection() throws SQLException {
    return ds.getConnection();
    }

    /**
    * 释放资源
    */
    public static void close(Statement stmt,Connection conn){
    close(null,stmt,conn);
    }

    public static void close(ResultSet rs , Statement stmt, Connection conn){
    if(rs != null){
    try {
    rs.close();
    } catch (SQLException e) {
    e.printStackTrace();
    }
    }

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

    if(conn != null){
    try {
    conn.close();//归还连接
    } catch (SQLException e) {
    e.printStackTrace();
    }
    }
    }

    /**
    * 获取连接池方法
    */
    public static DataSource getDataSource(){
    return ds;
    }

    }

使用工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package cn.itcast.datasource.druid;

import cn.itcast.utils.JDBCUtils;

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

/**
* 使用新的工具类
*/
public class DruidDemo2 {

public static void main(String[] args) {
/*
* 完成添加操作:给account表添加一条记录
*/
Connection conn = null;
PreparedStatement pstmt = null;
try {
//1.获取连接
conn = JDBCUtils.getConnection();
//2.定义sql
String sql = "insert into t_class values(?,?)";
//3.获取pstmt对象
pstmt = conn.prepareStatement(sql);
//4.给?赋值
pstmt.setInt(1,200);
pstmt.setString(2,"class1");
//5.执行sql
int count = pstmt.executeUpdate();
System.out.println(count);
} catch (SQLException e) {
e.printStackTrace();
}finally {
//6. 释放资源
JDBCUtils.close(pstmt,conn);
}
}
}

Spring JdbcTemplate

它是spring框架中提供的一个对象,是对原始繁琐的Jdbc API对象的简单封装。spring框架为我们提供了很多的操作模板类。例如:操作关系型数据的JdbcTemplate和HibernateTemplate,操作nosql数据库的RedisTemplate,操作消息队列的JmsTemplate等等。

  • Spring框架对JDBC的简单封装。提供了一个JdbcTemplate对象简化JDBC的开发

  • 步骤:

    1. 导入jar包

    2. 创建JdbcTemplate对象。依赖于数据源DataSource

    1
    JdbcTemplate template = new JdbcTemplate(ds);
    1. 调用JdbcTemplate的方法来完成CRUD的操作
      * update():执行DML语句。增、删、改语句
    * ```queryForMap()```:查询结果将结果集封装为map集合,将列名作为key,将值作为value 将这条记录封装为一个map集合
    
         注意:这个方法查询的结果集长度只能是1
    
    * ```queryForList()```:查询结果将结果集封装为list集合
    
         ​    注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中
    
    * ```query()```:查询结果,将结果封装为JavaBean对象
    
     * query的参数:RowMapper
          一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装
                    * new BeanPropertyRowMapper<类型>(类型.class)
    
    * ```queryForObject()```:查询结果,将结果封装为对象
    
     * 一般用于聚合函数的查询
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    package cn.itcast.jdbctemplate;

    import cn.itcast.utils.JDBCUtils;
    import org.springframework.jdbc.core.JdbcTemplate;

    /**
    * JdbcTemplate入门
    */
    public class JdbcTemplateDemo1 {

    public static void main(String[] args) {
    //1.导入jar包
    //2.创建JDBCTemplate对象
    JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
    //3.调用方法
    String sql = "update t_class set classname = 'class2' where classno = ?";
    int count = template.update(sql, 200);
    System.out.println(count);
    }
    }

使用maven框架的步骤:

  • 导入spring-jdbc和spring-tx坐标

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.0.5.RELEASE</version>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.0.5.RELEASE</version>
    </dependency>
  • 创建数据库表和实体

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    //创建account表和Account实体
    public class Account {

    private String name;
    private double money;

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public double getMoney() {
    return money;
    }

    public void setMoney(double money) {
    this.money = money;
    }

    @Override
    public String toString() {
    return "Account{" +
    "name='" + name + '\'' +
    ", money=" + money +
    '}';
    }
    }
  • 创建JdbcTemplate对象

  • 执行数据库操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public class JdbcTemplateTest {
    @Test
    //测试JdbcTemplate开发步骤
    public void test1() throws PropertyVetoException {
    //创建数据源对象
    ComboPooledDataSource dataSource = new ComboPooledDataSource();
    dataSource.setDriverClass("com.mysql.jdbc.Driver");
    dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
    dataSource.setUser("root");
    dataSource.setPassword("root");

    JdbcTemplate jdbcTemplate = new JdbcTemplate();
    //设置数据源对象 知道数据库在哪
    jdbcTemplate.setDataSource(dataSource);
    //执行操作
    int row = jdbcTemplate.update("insert into account values(?,?)", "tom", 5000);
    System.out.println(row);
    }
    }

Spring产生JdbcTemplate对象

我们可以将JdbcTemplate的创建权交给Spring,将数据源DataSource的创建权也交给Spring,在Spring容器内部将数据源DataSource注入到JdbcTemplate模版对象中,配置如下:

applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!--加载jdbc.properties-->
<context:property-placeholder location="classpath:jdbc.properties"/>

<!--数据源对象-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>

<!--jdbc模板对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
1
2
3
4
5
6
7
8
@Test
//测试Spring产生jdbcTemplate对象
public void test2() throws PropertyVetoException {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
JdbcTemplate jdbcTemplate = app.getBean(JdbcTemplate.class);
int row = jdbcTemplate.update("insert into account values(?,?)", "lisi", 5000);
System.out.println(row);
}

使用练习:

table emp格式:

  • 设计一个emp类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package cn.itcast.domain;

import java.util.Date;

public class Emp {
private Integer id;
private String ename;
private String job;
private Integer mgr;
private Date joindate;
private Double salary;
private Double bonus;
private Integer dept_id;


public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

public String getEname() {
return ename;
}

public void setEname(String ename) {
this.ename = ename;
}

public String getJob_id() {
return job;
}

public void setJob_id(String job) {
this.job = job;
}

public Integer getMgr() {
return mgr;
}

public void setMgr(Integer mgr) {
this.mgr = mgr;
}

public Date getJoindate() {
return joindate;
}

public void setJoindate(Date joindate) {
this.joindate = joindate;
}

public Double getSalary() {
return salary;
}

public void setSalary(Double salary) {
this.salary = salary;
}

public Double getBonus() {
return bonus;
}

public void setBonus(Double bonus) {
this.bonus = bonus;
}

public Integer getDept_id() {
return dept_id;
}

public void setDept_id(Integer dept_id) {
this.dept_id = dept_id;
}

@Override
public String toString() {
return "Emp{" +
"id=" + id +
", ename='" + ename + '\'' +
", job_id=" + job +
", mgr=" + mgr +
", joindate=" + joindate +
", salary=" + salary +
", bonus=" + bonus +
", dept_id=" + dept_id +
'}';
}
}
  • 使用Junit进行测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package cn.itcast.jdbctemplate;

import cn.itcast.domain.Emp;
import cn.itcast.utils.JDBCUtils;
import org.junit.Test;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

public class JdbcTemplateDemo2 {

//Junit单元测试,可以让方法独立执行


//1. 获取JDBCTemplate对象
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
/**
* 1. 修改1号数据的 salary 为 10000
*/
@Test
public void test1(){

//2. 定义sql
String sql = "update emp set SAL = 1000 where EMPNO = 7369";
//3. 执行sql
int count = template.update(sql);
System.out.println(count);
}

/**
* 2. 添加一条记录
*/
@Test
public void test2(){
String sql = "insert into emp(empno,ename,deptno) values(?,?,?)";
int count = template.update(sql, 1015, "郭靖", 10);
System.out.println(count);

}

/**
* 3.删除刚才添加的记录
*/
@Test
public void test3(){
String sql = "delete from emp where empno = ?";
int count = template.update(sql, 1015);
System.out.println(count);
}

/**
* 4.查询id为1001的记录,将其封装为Map集合
* 注意:这个方法查询的结果集长度只能是1
*/
@Test
public void test4(){
String sql = "select * from emp where empno = ? or empno = ?";
Map<String, Object> map = template.queryForMap(sql, 1015,7369);
System.out.println(map);
//{id=1001, ename=孙悟空, job_id=4, mgr=1004, joindate=2000-12-17, salary=10000.00, bonus=null, dept_id=20}

}

/**
* 5. 查询所有记录,将其封装为List
*/
@Test
public void test5(){
String sql = "select * from t_class";
List<Map<String, Object>> list = template.queryForList(sql);

for (Map<String, Object> stringObjectMap : list) {
System.out.println(stringObjectMap);
}
}

/**
* 6. 查询所有记录,将其封装为Emp对象的List集合
*/

@Test
public void test6(){
String sql = "select * from emp";
List<Emp> list = template.query(sql, new RowMapper<Emp>() {

@Override
public Emp mapRow(ResultSet rs, int i) throws SQLException {
Emp emp = new Emp();
int id = rs.getInt("EMPNO");
String ename = rs.getString("ENAME");
String job = rs.getString("JOB");
int mgr = rs.getInt("MGR");
Date joindate = rs.getDate("HIREDATE");
double salary = rs.getDouble("SAL");
double bonus = rs.getDouble("COMM");
int dept_id = rs.getInt("DEPTNO");

emp.setId(id);
emp.setEname(ename);
emp.setJob_id(job);
emp.setMgr(mgr);
emp.setJoindate(joindate);
emp.setSalary(salary);
emp.setBonus(bonus);
emp.setDept_id(dept_id);

return emp;
}
});


for (Emp emp : list) {
System.out.println(emp);
}
}

/**
* 6. 查询所有记录,将其封装为Emp对象的List集合
*/

@Test
public void test6_2(){
String sql = "select * from emp";
List<Emp> list = template.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class));
for (Emp emp : list) {
System.out.println(emp);
}
}

/**
* 7. 查询总记录数
*/

@Test
public void test7(){
String sql = "select count(empno) from emp";
Long total = template.queryForObject(sql, Long.class);
System.out.println(total);
}

}
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2022 ZHU
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信