jdbc通过连接池连接mysql数据库_JDBC02 利用JDBC连接数据库【使用数据库连接池】...

目录

1/2/3  Statement 和 Preparedstatement 的区别

4 读取properties配置文件

5 数据库连接池

6 利用数据库连接池连接数据库

1 使用Statement执行含有动态信息的SQL语句时有几个不足:

1.1 由于需要将动态数据拼接到SQL语句中,这导致程序复杂度高,容易出错

1.2 拼接的数据若含有SQL语法内容就会导致拼接后的SQL语法含义改变而出现SQL注入攻击

1.3 当大批量执行语义相同,但是含有动态数据的SQL时效率很差

2 使用Statement执行SQL语句不好的原因

2.1 当执行一条SQL语句发送到数据库时,数据库先将该SQL解析并生成一个执行计划(这个过程会消耗资源和性能),如果多次执行一样的SQL语句,数据库会重用执行计划,但是若多次执行语义相同但是含有动态数据的SQL时,数据库会生成不同的执行计划,严重影响数据库的开销

2.2 例如

执行 SELECT * FROM userifo_fury 生成一个执行计划再次执行SELECT * FROM userifo_fury 就会重用上面的执行计划(因为这是静态的SQL语句

但是,执行INSERT INTO userifo VALUES(1, 'JACK','122314','141234@QQ.COM','FURY',15600) )生成一个执行计划,再执行执行INSERT INTO userifo VALUES(2, 'rose','122314','141234@QQ.COM','FURY',15600)由于内容不同,会再次生成另外一个执行计划,若执行1000次上述情况的INSERT,数据库会产生1000个执行计划,这样就严重影响了数据库的效率

因此,Statement只适合执行静态的SQL语句,不适合执行动态的SQL语句

3 利用PreparedStatement代替Statement

编写简单

没有SQL注入问题

批量执行语义相同的SQL语句会重用执行计划

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagecn.xiangxu.entity;2

3 importjava.io.Serializable;4

5 public class User implementsSerializable {6

7 private static final long serialVersionUID = -5109978284633713580L;8

9 privateInteger id;10 privateString name;11 privateString pwd;12 publicUser() {13 super();14 //TODO Auto-generated constructor stub

15 }16 publicUser(Integer id, String name, String pwd) {17 super();18 this.id =id;19 this.name =name;20 this.pwd =pwd;21 }22 @Override23 public inthashCode() {24 final int prime = 31;25 int result = 1;26 result = prime * result + ((id == null) ? 0: id.hashCode());27 returnresult;28 }29 @Override30 public booleanequals(Object obj) {31 if (this ==obj)32 return true;33 if (obj == null)34 return false;35 if (getClass() !=obj.getClass())36 return false;37 User other =(User) obj;38 if (id == null) {39 if (other.id != null)40 return false;41 } else if (!id.equals(other.id))42 return false;43 return true;44 }45 publicInteger getId() {46 returnid;47 }48 public voidsetId(Integer id) {49 this.id =id;50 }51 publicString getName() {52 returnname;53 }54 public voidsetName(String name) {55 this.name =name;56 }57 publicString getPwd() {58 returnpwd;59 }60 public voidsetPwd(String pwd) {61 this.pwd =pwd;62 }63 @Override64 publicString toString() {65 return "User [id=" + id + ", name=" + name + ", pwd=" + pwd + "]";66 }67

68

69

70 }

user表对应的实体类

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagetestJDBC;2

3 importjava.sql.Connection;4 importjava.sql.DriverManager;5 importjava.sql.PreparedStatement;6 importjava.sql.ResultSet;7 importjava.sql.SQLException;8 importjava.util.ArrayList;9 importjava.util.List;10

11 importorg.junit.Test;12

13 importcn.xiangxu.entity.User;14

15 public classTestCase {16 @Test17 public voidtest01() {18 Connection conn = null;19 PreparedStatement ps = null;20 ResultSet rs = null;21 try{22 Class.forName("com.mysql.jdbc.Driver"); //加载数据库驱动

23

24 conn = DriverManager.getConnection( //初始化连接对象

25 "jdbc:mysql://localhost:3306/test", "root", "182838");26

27

28 String sql = "SELECT * FROM user WHERE pwd = ? "; //拼接SQL语句,位置参数用?代替

29

30 ps = conn.prepareStatement(sql); //初始化预编译执行对象

31

32 ps.setString(1, "182838"); //设置SQL语句中的位置位置参数(注意:是从1开始数不是从0开始数)

33

34 rs = ps.executeQuery(); //执行SQL语句

35

36 List users = new ArrayList(); //创建一个集合来存放记录对象

37 while(rs.next()) { //遍历结果集38 //System.out.println("====================");39 //System.out.println(rs.getInt("id"));40 //System.out.println(rs.getString("name"));41 //System.out.println(rs.getString("pwd"));

42 User user = newUser();43 user.setId(rs.getInt("id"));44 user.setName(rs.getString("name"));45 user.setPwd(rs.getString("pwd"));46 users.add(user); //向集合中添加元素

47 }48

49 System.out.println(users); //打印输出集合

50 for(User user : users) {51 System.out.println(user);52 }53

54 //释放资源

55 rs.close();56 ps.close();57 conn.close();58

59 } catch(Exception e) {60 //TODO Auto-generated catch block

61 e.printStackTrace();62 } finally{63 if(rs != null) {64 try{65 rs.close();66 } catch(SQLException e) {67 //TODO Auto-generated catch block

68 e.printStackTrace();69 }70 }71 if(ps != null) {72 try{73 ps.close();74 } catch(SQLException e) {75 //TODO Auto-generated catch block

76 e.printStackTrace();77 }78 }79 if(conn != null) {80 try{81 conn.close();82 } catch(SQLException e) {83 //TODO Auto-generated catch block

84 e.printStackTrace();85 }86 }87 }88

89 }90

91 }

使用预编译Statement的实例

4 利用Properties对象读取properties配置文件中的信息

4.1 Properties继承了Hashtable类,Properties对象也是使用键值对的方式来保存数据,但是Properties对象的键和值都是字符串类型

class Properties extends Hashtable

4.2 Properties 类中的主要方法

4.2.1 public synchronized voidload(InputStream inStream) throws IOException

将properties属性文件的文件输入流加载到Properties对象

f168bfff4091bea59301885e20526c3e.png

4.2.2 public void store(OutputStream out, String comments) throws IOException

将Properties对象中的属性列表保存到输出流文件中

d3d30273bc851cbc09462639ba923cd5.png

注意:第二个参数表示注释信息(注意:properties文件中不能用中文),在注释信息后面会自动添加一个时间信息

注意:新创建的文件在项目的根目录下面(问题:为什么在eclipse中没有,但是到文件夹中却能找到???)

4.2.3 public StringgetProperty(String key)

获取属性值,参数是属性的键

4.2.4 public synchronized Object setProperty(String key, String value)

修改属性值,参数1是属性的键,参数2是属性的新值

4.3 案例

要求:读取properties配置文件总的属性值,将读取到的属性值进行修改后保存到另外一个properties配置文件中

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagecn.xiangxu.entity;2

3 importjava.io.FileInputStream;4 importjava.io.FileOutputStream;5 importjava.io.InputStream;6 importjava.util.Iterator;7 importjava.util.Properties;8

9 public classTest {10 public static voidmain(String[] args) {11 try{12 Properties prop = new Properties(); //创建Properties对象13

14 //prop.load(new FileInputStream("config.properties"));//使用这种方式时,配置文件必须放在项目的根目录下

15 InputStream is = Test.class.getClassLoader().getResourceAsStream("config/config.properties"); //读取属性文件

16

17 prop.load(is); //加载属性列表

18

19 Iterator it=prop.stringPropertyNames().iterator(); //将配置文件中的所有key放到一个可迭代对象中

20 while(it.hasNext()){ //利用迭代器模式进行迭代

21 String key=it.next(); //读取下一个迭代对象的下一个元素

22 System.out.println(key+":"+prop.getProperty(key)); //根据key值获取value值(获取属性信息)

23 }24

25 is.close(); //关闭输入流,释放资源

26

27 FileOutputStream oFile = new FileOutputStream("b.properties", true);//创建一个输出流文件,true表示追加打开

28 prop.setProperty("maxactive", "33"); //修改属性信息

29 prop.store(oFile, "zhe shi yi ge xin de shu xing pei zhi wen jian."); //将Properties对象中的内容放到刚刚创建的文件中去

30 oFile.close(); //关闭输出流,释放资源

31

32 } catch(Exception e) {33 //TODO Auto-generated catch block

34 e.printStackTrace();35 }36 }37 }

读取属性配置文件信息

等待读取的properties配置文件的位置如下图所示

aa375313c7021d37ac48c1ee77ba0172.png

5 数据库连接池

5.1 什么是数据库连接池

程序启动时就创建足够多的数据库连接,并将这些连接组成一个连接池,由程序自动地对池中的连接进行申请、使用、释放

5.2 数据库连接池的运行机制

》程序初始化时创建连接池

》需要操作数据库时向数据库连接池申请一个可用的数据库连接

》使用完毕后就将数据库连接还给数据库连接池(注意:不是关闭连接,而是交给连接池)

》整个程序退出时,断开所有连接,释放资源(即:管理数据库连接池的那个线程被杀死后才关闭所有的连接)

ad60cdce08f34630b9a8a65d4c289ed1.png

5.3 数据库连接池的编程步骤

5.3.1 导包

9283238e2bdbe06daf492c6bfe868406.png

5.3.2 声明ThreadLocal、BasicDataSource成员变量(注意:这两个成员变量是静态的)

aef9c07497e6eba245bdd64674b8f933.png

5.3.3 在静态代码块中实例化那两个成员变量,并通过Properties对象读取配置文件信息,利用这些配置文件信息给BasicDataSource对象进行初始化处理

8df514ac87026f9c371b39490d73b1f0.png

5.3.4 编写创建连接静态方法

利用BasicDataSource对象实例化一个连接对象

将这个连接对象放到ThreadLocal对象中

6be4c9b8ccce2bd989fb51fd3d8d4f29.png

5.3.5 编写释放连接静态方法

从ThreadLocal对象中获取连接对象

清空ThreadLocal对象

判断连接对象是否释放

f9d27d5742b11f980333d7c11cf31c41.png

6 利用数据库连接池操作数据库

项目结构图

bb11cffcd361dc76322d02cceff65218.png

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 # zhe shi zhu shi , yi ban bu yong zhong wen2 # deng hao liang bian mei you kong ge, mo wei mei you fen hao3 # hou mian bu neng you kong ge4 driverClassName=com.mysql.jdbc.Driver5 url=jdbc:mysql://localhost:3306/test6 username=root7 password=1828388 maxActive=1009 maxWait=3000

properties配置文件

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1

2 4.0.0

3 cn.xiangxu

4 testJDBC

5 0.0.1-SNAPSHOT

6

7

8 mysql

9 mysql-connector-java

10 5.1.37

11

12

13 junit

14 junit

15 4.12

16

17

18 commons-dbcp

19 commons-dbcp

20 1.4

21

22

23

maven依赖文件

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagecn.xiangxu.tools;2

3 importjava.io.IOException;4 importjava.io.InputStream;5 importjava.sql.Connection;6 importjava.sql.SQLException;7 importjava.util.Properties;8

9 importorg.apache.commons.dbcp.BasicDataSource;10

11 public classDBUtil {12 /*

13 * ThreadLocal用于线程跨方法共享数据使用14 * ThreadLocal内部有一个Map, key为需要共享数据的线程本身,value就是其需要共享的数据15 */

16 private static ThreadLocal tl; //声明一个类似于仓库的东西

17 private static BasicDataSource dataSource; //声明一个数据库连接池对象18

19 //静态代码块,在类加载的时候执行,而且只执行一次

20 static{21 tl = new ThreadLocal(); //实例化仓库对象

22 dataSource = new BasicDataSource(); //实例数据库连接池对象

23

24 Properties prop = new Properties(); //创建一个Properties对象用(该对象可以用来加载配置文件中的属性列表)

25 InputStream is = DBUtil.class.getClassLoader().getResourceAsStream("config/mysql.properties"); //读取配置文件信息

26 try{27 prop.load(is); //加载配置文件中的属性列表

28

29 String driverClassName = prop.getProperty("driverClassName"); //获取属性信息

30 String url = prop.getProperty("url");31 String username = prop.getProperty("username");32 String password = prop.getProperty("password");33 Integer maxActive = Integer.parseInt(prop.getProperty("maxActive"));34 Integer maxWait = Integer.parseInt(prop.getProperty("maxWait"));35

36 dataSource.setDriverClassName(driverClassName); //初始化数据库连接池(即:配置数据库连接池的先关参数)

37 dataSource.setUrl(url);38 dataSource.setUsername(username);39 dataSource.setPassword(password);40 dataSource.setMaxActive(maxActive);41 dataSource.setMaxWait(maxWait);42

43 is.close(); //关闭输入流,释放资源

44 } catch(IOException e) {45 //TODO Auto-generated catch block

46 e.printStackTrace();47 }48

49 }50

51 /**

52 * 创建连接对象(注意:静态方法可以直接通过类名来调用)53 *@return连接对象54 *@throwsException55 */

56 public static Connection getConnection() throwsException {57 try{58 Connection conn = dataSource.getConnection(); //创建连接对象(利用数据库连接池进行创建)

59 tl.set(conn); //将连接对象放到仓库中

60 returnconn;61 } catch(Exception e) {62 //TODO Auto-generated catch block

63 e.printStackTrace();64 throwe;65 }66 }67

68 /**

69 * 关闭连接对象(注意:静态方法可以通过类名直接调用)70 *@throwsException71 */

72 public static void closeConnection() throwsException {73 Connection conn = tl.get(); //从仓库中取出连接对象

74 tl.remove(); //清空仓库

75 if(conn != null) { //判断连接对象是否释放资源

76 try{77 conn.close();78 } catch(Exception e) {79 //TODO Auto-generated catch block

80 e.printStackTrace();81 throwe;82 }83 }84 }85

86 }

数据库连接池类

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 packagetestJDBC;2

3 importjava.sql.Connection;4 importjava.sql.PreparedStatement;5 importjava.sql.ResultSet;6

7 importorg.junit.Test;8

9 importcn.xiangxu.tools.DBUtil;10

11 public classTestDBUtil {12 @Test13 public voidtest01() {14 try{15 Connection conn = DBUtil.getConnection(); //创建连接对象

16 String sql = "SELECT * FROM user "; //拼接SQL语句

17 PreparedStatement ps = conn.prepareStatement(sql); //创建执行对象

18 ResultSet rs = ps.executeQuery(sql); //执行SQL语句

19 while(rs.next()) { //遍历结果集

20 System.out.println(rs.getString("name"));21 }22 } catch(Exception e) {23 e.printStackTrace();24 } finally { //关闭连接,释放资源

25 try{26 DBUtil.closeConnection();27 } catch(Exception e) {28 e.printStackTrace();29 }30 }31 }32 }

数据库连接池的应用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值