版权声明:本文为博主原创文章,转载请注明出处:https://blog.youkuaiyun.com/qq_41922058
一、如何多线程操作事务
1.source
package jdbc;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
public class Demo02 {
public Demo02() {
for (int i = 1; i <= 5; i++) {
new t().start();
}
}
class t extends Thread {
public void run() {
System.err.println("1:获取连接");
Connection con = DsUtils.getCon();
System.err.println(con);
try {
System.err.println("2:设置事务提交方式");
con.setAutoCommit(false);
System.err.println("3:写入数据");
Statement st = con.createStatement();
String name = getName();
st.executeUpdate("insert into users values('景玺','" + name + "')");
// System.err.println("4:启动线程2");
// t2.start();
// System.err.println("5:阻塞");
// new Scanner(System.in).nextLine();
System.err.println("4:提交数据");
con.commit();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
con.setAutoCommit(true);
System.err.println("12:关闭连接");
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
};
};
//
// Thread t2 = new Thread() {
//
// public void run() {
//
// System.err.println("6:获取连接");
// Connection con = ConnUtils1.getCon();
// System.err.println(con);
// try {
// System.err.println("7:设置事务提交方式");
// con.setAutoCommit(false);
// System.err.println("8:写入数据");
// Statement st = con.createStatement();
// String name = getName()+","+con;
// st.executeUpdate("insert into users values('景玺','"+name+"')");
// System.err.println("9:提交数据");
// con.commit();
// } catch (SQLException e) {
// e.printStackTrace();
// } finally {
// try {
//
// System.err.println("10:关闭连接");
// con.close();
// } catch (SQLException e) {
// e.printStackTrace();
// }
// }
//
// };
// };
public static void main(String[] args) {
new Demo02();
}
}
2. 多线程操作事务存在的问题
假如只有一个con:多个线程进行操作事务,处理速度会非常的慢,管理不好con,则造成con关闭不能重用问题。
3. 解决思路
开发一个连接池,保存con并进行合适的管理
二、连接池原理
1. 实现多个连接的封装
第一步:private static List<Connection> list = new LinkedList<>();
声明linkedlist数据结构用于保存con,链表数据结构优点,能进行快速的增删数据
第二步:通过for循环创建多个con对象;
第三步:通过list.add(); 方法将con 保存到链表中;
第四步:创建getCon(); 方法获取返回con对象;
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
public class ConnUtils1 {
private static List<Connection> list = new LinkedList<>();
static {
try {
Properties pro = new Properties();
pro.load(ClassLoader.getSystemResourceAsStream("jdbc.properties"));
String driver = pro.getProperty("driver");
String url = pro.getProperty("url");
String name = pro.getProperty("name");
String psd = pro.getProperty("psd");
Class.forName(driver);
for(int i =1 ; i <= 3; i++ ) {
Connectioncon = DriverManager.getConnection(url, name, psd);
list.add(con);
}
} catch (Exception e) {
System.err.println("连接数据库异常");
}
}
public static Connection getCon() {
synchronized (list) {
if(list.size() == 0) {
try {
list.wait();
} catch (InterruptedException e) {
}
}
Connection con = list.remove(0);
return con;
}
}
}
2. 声明方法con使用完成进行归还
public static void backCon(Connection con) {
synchronized (list) {
list.add(con);
list.notify();
}
3. 增强close();
使用包装模式:实现A,并且含有A的成员变量
注意:包装模式需要实现接口当中的所有方法;
private static class MyConnection implements Connection{
private Connection mycon;
public MyConnection(Connection con) {
this.mycon = con;
}
@Override
public void close() throws SQLException {
synchronized (list) {
list.add(this);
list.notify();
}
}
此时应该创建MyConnection对象进行包装con
MyConnection mycon = new MyConnection(con);
list.add(mycon);
当程序员调用con.close();时,连接不会关闭,而会向list进行归还con;
三、开发标准连接池
1. 实现DataSource接口:
public class MyDataSource implements DataSource {}
2.实现接口中的getConnection方法
public class MyDataSource implements DataSource {
@Override
public Connection getConnection() throws SQLException {
synchronized (list) {
if (list.size() == 0) {
try {
list.wait();
} catch (InterruptedException e) {
}
}
Connection con = list.remove(0);
return con;
}
}
}
3.代码展示(只展示重要方法,不代表其他方法不需要实现)
package jdbc;
Import ...;
public class MyDataSource implements DataSource {
private List<Connection> list = new LinkedList<>();
public MyDataSource() {
try {
Properties pro = new Properties();
pro.load(ClassLoader.getSystemResourceAsStream("jdbc.properties"));
String driver = pro.getProperty("driver");
String url = pro.getProperty("url");
String name = pro.getProperty("name");
String psd = pro.getProperty("psd");
Class.forName(driver);
for (int i = 1; i <= 3; i++) {
Connection con = DriverManager.getConnection(url, name, psd);
MyConnection mycon = new MyConnection(con);
list.add(mycon);
}
} catch (Exception e) {
System.err.println("连接数据库异常");
}
}
@Override
public Connection getConnection() throws SQLException {
synchronized (list) {
if (list.size() == 0) {
try {
list.wait();
} catch (InterruptedException e) {
}
}
Connection con = list.remove(0);
return con;
}
}
private class MyConnection implements Connection {
private Connection mycon;
public MyConnection(Connection con) {
this.mycon = con;
}
@Override
public void close() throws SQLException {
synchronized (list) {
list.add(this);
list.notify();
}
}
}
4.常用第三方连接池
C3P0
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。
DBCP
DBCP(DataBase Connection Pool)数据库连接池,是java数据库连接池的一种,由Apache开发,通过数据库连接池,可以让程序自动管理数据库连接的释放和断开。