JDBC

练习

myguests表:

avatar

avatar

  • 定义一个方法,查询myguests表的数据将其封装为对象。然后装载集合,返回

    1. 定义一个Myguests类

    2. 定义方法public List findAll(){}

    3. 实现方法 select * from Myguests

创建一个Myguests类

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
package jdbc.test;

/**
* 封装Myguests表数据的JavaBean
*/

public class Myguests {
private int id;
private String firstname;
private String lastname;
private String email;

public int getId() {
return id;
}

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

public String getFirstname() {
return firstname;
}

public void setFirstname(String firstname) {
this.firstname = firstname;
}

public String getLastname() {
return lastname;
}

public void setLastname(String lastname) {
this.lastname = lastname;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

@Override
public String toString() {
return "Myguests{" +
"id=" + id +
", firstname='" + firstname + '\'' +
", lastname='" + lastname + '\'' +
", email='" + email + '\'' +
'}';
}
}

创建demo8

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
package jdbc;

import jdbc.test.Myguests;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class demo8 {
public List<Myguests> findAll() {
Connection conn=null;
Statement stmt=null;
ResultSet rs=null;
List<Myguests> list=null;
try {
//1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接对象
conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=GMT%2B8","root","root");
//3.sql语句
String sql="select * from myguests";
//4.获取执行sql对象
stmt=conn.prepareStatement(sql);
//5.执行sql
rs=stmt.executeQuery(sql);
//6.遍历结果集,封装对象,装载集合
Myguests myguests=null;
list = new ArrayList<Myguests>();
while(rs.next()){
//获取数据
int id=rs.getInt("id");
String fristname=rs.getString("firstname");
String lastname = rs.getString("lastname");
String email = rs.getString("email");
//创建对象,并赋值
myguests=new Myguests();
myguests.setId(id);
myguests.setFirstname(fristname);
myguests.setLastname(lastname);
myguests.setEmail(email);

//装载集合
list.add(myguests);
}

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

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();
}
}

}
return list;
}

public static void main(String[] args) {
List<Myguests> list = new demo8().findAll();
System.out.println(list);
}
}

运行结果
1
[Myguests{id=1, firstname='John', lastname='Doe', email='john@example.com'}, Myguests{id=2, firstname='John', lastname='Doe', email='john@example.com'}, Myguests{id=3, firstname='Mary', lastname='Moe', email='mary@example.com'}, Myguests{id=4, firstname='Julie', lastname='Dooley', email='julie@example.com'}, Myguests{id=5, firstname='John', lastname='Doe', email='john@example.com'}, Myguests{id=6, firstname='Mary', lastname='Moe', email='mary@example.com'}, Myguests{id=7, firstname='Julie', lastname='Dooley', email='julie@example.com'}]

工具类

  • 目的:简化书写

  • 分析:

    1. 注册驱动也抽取

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

      • 需求:不想传递参数,还得保证工具类的通用性

      • 解决方案:配置文件

    3. 抽取一个方法释放资源

创建JDBCUtils

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
package jdbc.until;

import java.io.FileReader;
import java.io.IOException;
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();

//2.加载文件
pro.load(new FileReader("src/main/java/jdbc.properties"));

//3.获取数据,赋值
url=pro.getProperty("url");
user=pro.getProperty("user");
password=pro.getProperty("password");
driver=pro.getProperty("driver");

//4.注册驱动
Class.forName(driver);
} catch (IOException | 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();
}
}

}

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();
}
}
}
}

配置文件

1
2
3
4
url=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=GMT%2B8
user=root
password=root
driver=com.mysql.cj.jdbc.Driver

修改demo8中的findAll()方法

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
package jdbc;

import jdbc.test.Myguests;
import jdbc.until.JDBCUtils;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class demo8 {
public List<Myguests> findAll() {
Connection conn=null;
Statement stmt=null;
ResultSet rs=null;
List<Myguests> list=null;
try {
//1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接对象
conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=GMT%2B8","root","root");
//3.sql语句
String sql="select * from myguests";
//4.获取执行sql对象
stmt=conn.prepareStatement(sql);
//5.执行sql
rs=stmt.executeQuery(sql);
//6.遍历结果集,封装对象,装载集合
Myguests myguests=null;
list = new ArrayList<Myguests>();
while(rs.next()){
//获取数据
int id=rs.getInt("id");
String fristname=rs.getString("firstname");
String lastname = rs.getString("lastname");
String email = rs.getString("email");
//创建对象,并赋值
myguests=new Myguests();
myguests.setId(id);
myguests.setFirstname(fristname);
myguests.setLastname(lastname);
myguests.setEmail(email);

//装载集合
list.add(myguests);
}

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

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();
}
}

}
return list;
}

/**
* 演示JDBC工具类
* @return
*/
public List<Myguests> findAll2() {
Connection conn=null;
Statement stmt=null;
ResultSet rs=null;
List<Myguests> list=null;
try {
conn=JDBCUtils.getConnection();
//3.sql语句
String sql="select * from myguests";
//4.获取执行sql对象
stmt=conn.prepareStatement(sql);
//5.执行sql
rs=stmt.executeQuery(sql);
//6.遍历结果集,封装对象,装载集合
Myguests myguests=null;
list = new ArrayList<Myguests>();
while(rs.next()){
//获取数据
int id=rs.getInt("id");
String fristname=rs.getString("firstname");
String lastname = rs.getString("lastname");
String email = rs.getString("email");
//创建对象,并赋值
myguests=new Myguests();
myguests.setId(id);
myguests.setFirstname(fristname);
myguests.setLastname(lastname);
myguests.setEmail(email);

//装载集合
list.add(myguests);
}

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

public static void main(String[] args) {
List<Myguests> list = new demo8().findAll2();
System.out.println(list);
}
}

JDBC登录案例

需求:

  • 通过键盘录入用户名和密码

  • 判断用户是否登录成功

    • select * from user where username=”” and password=””;

    • 如果这个sql有查询结果,则成功,反之,则失败

步骤:

  1. 创建数据库表user表

    • create table user(
      id int primary key auto_increment,
      username varchar(32),
      password varchar(32));

      insert into user values(null,’zhangsan’,’123’);

      insert into user values(null,’lisi’,’234’);

创建demo9

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
package jdbc;

import jdbc.until.JDBCUtils;

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

/**
* 需求:
*通过键盘录入用户名和密码
*判断用户是否登录成功
*/

public class demo9 {
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 demo9().login(username, password);
//3.判断结果,输出不同语句
if(flag){
System.out.println("登录成功");
}else{
System.out.println("用户名或密码错误");
}
}

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

} catch (SQLException e) {
e.printStackTrace();
}finally {
//释放资源
JDBCUtils.close(rs,stmt,conn);
}
return false;
}
}

记得根据自身数据库不同,对配置文件进行修改

如果输入正确 那么运行结果为

1
2
3
4
5
请输入用户名
zhangsan
请输入密码
123
登录成功

如果输入不正确
1
2
3
4
5
请输入用户名
zhangsan
请输入密码
11111
用户名或密码错误

PreparedStatement

demo9的案例,其实会有一个bug,存在sql注入的安全问题

例如

1
2
3
4
5
请输入用户名
51nd0re1
请输入密码
1' or '1' = '1
登录成功

可以看到用户名和密码都不在数据库中,但是却输出登录成功了

  1. SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接,会造成安全性问题

    1. 输入用户随便,输入密码:1’ or ‘1’ = ‘1

    2. sql:select * from user where username=’51nd0re1’ and password=’1’ or ‘1’ = ‘1’

  2. 解决sql注入问题:使用PreparedStatement对象来解决

  3. 预编译sql:参数使用?来作为占位符

  4. 步骤:

    1. 导入驱动jar
    2. 注册驱动
    3. 获取数据库连接对象
    4. 定义sql(使用?作为占位符)
    5. 获取执行sql语句的对象
    6. 给?赋值
      • 方法:setXxx(参数1,参数2)
      • 参数1:?的位置编号从1开始
      • 参数2:?的值
    7. 执行sql,接受返回结果,不需要传递sql语句
    8. 处理结果
    9. 释放资源
  5. 注意:后期都会使用PreparedStatement来完成增删改查的所有操作

    1. 可以防止sql注入

    2. 效率更高

修改demo9

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
package jdbc;

import jdbc.until.JDBCUtils;

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

/**
* 需求:
*通过键盘录入用户名和密码
*判断用户是否登录成功
*/

public class demo9 {
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 demo9().login(username, password);
//3.判断结果,输出不同语句
if(flag){
System.out.println("登录成功");
}else{
System.out.println("用户名或密码错误");
}
}

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

} catch (SQLException e) {
e.printStackTrace();
}finally {
//释放资源
JDBCUtils.close(rs,pstmt,conn);
}
return false;
}
}

运行结果
1
2
3
4
5
请输入用户名
51nd0re1
请输入密码
1' or '1' = '1
用户名或密码错误

解决了sql注入的问题

JDBC控制事务

  1. 事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败

  2. 操作

    1. 开启事务 getAutoCommit(boolean autoCommit) 调用该方法设置参数为false,即开启事务

    2. 提交事务 commit()

    3. 回滚事务 rollback()

演示

avatar
这是原本表中的数据

创建demo10

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
package jdbc;

import jdbc.until.JDBCUtils;

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

/**
* 事务操作
*/

public class demo10 {

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){
//事务回滚
if(conn!=null){
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
e.printStackTrace();

}finally {
JDBCUtils.close(pstmt1,conn);
JDBCUtils.close(pstmt2,null);
}
}

}

在操作执行前开启事务,最后提交事务,在异常的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
61
62
63
64
package jdbc;

import jdbc.until.JDBCUtils;

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

/**
* 事务操作
*/

public class demo10 {

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){
//事务回滚
if(conn!=null){
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
e.printStackTrace();

}finally {
JDBCUtils.close(pstmt1,conn);
JDBCUtils.close(pstmt2,null);
}
}

}

运行结果
avatar

数据库连接池

概念

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

好处

  1. 节约资源

  2. 用户访问高效

实现

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

    1. 获取连接 getConnection()

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

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

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

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

c3p0

  • 步骤:

    1. 导入jar包 c3p0-0.9.5.2.jar mchange-common-java-0.2.20.jar

    2. 定义配置文件:c3p0.properties 或者 c3p0-config.xml;路径直接将文件放在src目录下即可

    3. 创建核心对象 数据库连接池都西昂 ComboPooledDataSource

    4. 获取连接 getConnection

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package jdbc.datasource.c3p0;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

public class demo1 {
public static void main(String[] args) throws SQLException {
//1.创建数据库连接池对象
DataSource ds=new ComboPooledDataSource();
//2.获取连接对象
Connection conn = ds.getConnection();
//3.打印
System.out.println(conn);

}
}

运行结果

1
2
3
4
5
6
7
七月 28, 2020 3:32:11 下午 com.mchange.v2.log.MLog 
信息: MLog clients using java 1.4+ standard logging.
七月 28, 2020 3:32:11 下午 com.mchange.v2.c3p0.C3P0Registry
信息: Initializing c3p0-0.9.5.5 [built 11-December-2019 22:18:33 -0800; debug? true; trace: 10]
七月 28, 2020 3:32:12 下午 com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource
信息: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> 1b61k3gab155opvmvrn7zd|6659c656, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.cj.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 1b61k3gab155opvmvrn7zd|6659c656, idleConnectionTestPeriod -> 0, initialPoolSize -> 10, jdbcUrl -> jdbc:mysql://localhost:3306/db?useSSL=false&serverTimezone=Hongkong&characterEncoding=utf-8&autoReconnect=true, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 30, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 100, maxStatements -> 200, maxStatementsPerConnection -> 0, minPoolSize -> 10, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]
com.mchange.v2.c3p0.impl.NewProxyConnection@224aed64 [wrapping: com.mysql.cj.jdbc.ConnectionImpl@bff90cc]

前面的都是日志信息

10个对象获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package jdbc.datasource.c3p0;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

public class demo2 {
public static void main(String[] args) throws SQLException {
//1.获取DataSource
DataSource ds= new ComboPooledDataSource();
//2.获取连接
for (int i=1;i<=10;i++){
Connection conn = ds.getConnection();
System.out.println(i+":"+conn);
}
}
}

可以看到hash值都不一样,证明是10个不同的对象

当配置文件最大对象数为10时
如果设置11个对象,就会出现报错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package jdbc.datasource.c3p0;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

public class demo2 {
public static void main(String[] args) throws SQLException {
//1.获取DataSource
DataSource ds= new ComboPooledDataSource();
//2.获取连接
for (int i=1;i<=11;i++){
Connection conn = ds.getConnection();
System.out.println(i+":"+conn);
}
}
}

运行结果
1
Exception in thread "main" java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.

如果想要第11个对象访问,就需要在1-10对象之间,任意归还一个到连接池中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package jdbc.datasource.c3p0;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

public class demo2 {
public static void main(String[] args) throws SQLException {
//1.获取DataSource
DataSource ds= new ComboPooledDataSource();
//2.获取连接
for (int i=1;i<=11;i++){
Connection conn = ds.getConnection();
System.out.println(i+":"+conn);

if (i==5){
conn.close();//归还连接到连接池中
}
}
}
}

这也就不会报错了,但是可以看到第5个和第6个的hash值时相同的,也就意味着应用的是同一个资源

druid

  • 步骤:

    1. 导入jar包 druid-1.1.23 jar

    2. 定义配置文件:

      • 是properties形式的

      • 可以叫任意名称,可以放在任意目录下

    3. 加载配置文件,Properties

    4. 获取数据库连接池对象:通过工厂类来获取的 DruidDataSourceFactory

    5. 获取连接:getConnection

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
package jdbc.datasource.druid;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.FileReader;
import java.sql.Connection;
import java.util.Properties;

public class demo1 {
public static void main(String[] args) throws Exception {
//1.导入jar包
//2.定义配置文件
//3.加载配置文件
Properties pro = new Properties();
pro.load(new FileReader("src/main/resources/druid.properties"));
//4.获取连接池对象
DataSource ds = DruidDataSourceFactory.createDataSource(pro);
//5.获取连接
Connection conn=ds.getConnection();
System.out.println(conn);

}
}

运行结果

1
2
3
七月 28, 2020 4:47:41 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
com.mysql.cj.jdbc.ConnectionImpl@3a82f6ef

工具类

  • 定义工具类

    1. 定义一个类 JDBCUtils

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

    3. 提供方法

      1. 获取连接方法:通过数据库连接池获取连接
      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
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
package jdbc.until;

import com.alibaba.druid.pool.DruidDataSourceFactory;

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

/**
* Druid连接池的工具类
*/


public class JDBCUtils2 {
//1.定义一个成员变量 DataSource
private static DataSource ds;

static {
try {
//1.加载配置文件
Properties pro=new Properties();
pro.load(JDBCUtils2.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){
if(stmt!=null){
try {
stmt.close();
}catch (SQLException e){
e.printStackTrace();
}
}

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

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
package jdbc.datasource.druid;

import jdbc.until.JDBCUtils2;

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

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

运行结果

1
2
3
七月 28, 2020 5:12:41 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
1

avatar

Spring JDBC

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

  • 步骤

    1. 导入jar包

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

      • JdbcTemplate template = new JdbcTemplate(ds)
    3. 调用方法来JdbcTemplate的方法来完成CRUD的操作

      • update()执行DML语句。增删改语句

      • queryForMap() 查询结果将结果集封装为map集合

      • queryForList() 查询结果将结果集封装为list集合

      • query() 查询结果,将结果封装为JavaBean对象

      • queryForObject 查询结果,将结果封装为对象

快速入门

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
package jdbc.datasource.jdbctemplate;

import jdbc.until.JDBCUtils2;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;

/**
* JdbcTemplate入门
*/


public class demo1 {
public static void main(String[] args) {
//1.导入jar包
//2.创建JDBCTemplate对象
JdbcTemplate template=new JdbcTemplate(JDBCUtils2.getDataSource());
//3.调用方法
String sql="update account set balance=5000 where id = ?";
try{
int count = template.update(sql,3);
System.out.println(count);
}catch (DataAccessException e){
e.printStackTrace();
}

}
}

运行结果

1
2
3
七月 28, 2020 5:59:48 下午 com.alibaba.druid.support.logging.JakartaCommonsLoggingImpl info
信息: {dataSource-1} inited
1

avatar