连接池与事务处理:)
连接池
连接池的概念
连接池(datasource),也叫**数据源**。本质上就是一个存储多个连接对象的容器.
在使用连接时,连接池提供一个连接对象.使用完连接对象后,连接池会将连接对象回收在容器中.
连接池的优点:**节省创建连接与释放连接的时间,减少了性能消耗.提高了连接对象的复用率.**
c3p0连接池的使用
c3p0连接池介绍
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate、Spring等。
使用步骤
可以使用手动编码的方式(但是不推荐,也不灵活),在写项目中常用配置文件的方式来对连接池进行设置(推荐)
- 1.在项目中引入c3p0的jar包
记得Build path
- 2.编写c3p0的配置文件
在项目的类路径下,创建配置文件,该文件的名称最好必须为:c3p0-config.xml.配置如下:
点我获取c3p0jar包密码:037s
<?xml version="1.0" encoding="UTF-8"?>
<!--c3p0的配置信息-->
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/数据库名称</property>
<property name="user">数据库用户名</property>
<property name="password">数据库用户密码</property>
<property name="initialPoolSize">5</property> //连接池初始化个数设置
<property name="acquireIncrement">3</property> //如果不够用的话进行增加的个数
</default-config>
</c3p0-config>
- 3.书写代码获取连接对象,连接数据库,执行sql.
栗子:
public class Test {
public static void main(String[]arg) throws SQLException {
ComboPooledDataSource cpds = new ComboPooledDataSource();
Connection connection = cpds.getConnection();
String sql = "select * from student";
PreparedStatement prepareStatement = connection.prepareStatement(sql);
ResultSet executeQuery = prepareStatement.executeQuery();
while(executeQuery.next()) {
System.out.print(executeQuery.getObject(1) + "\t");
System.out.print(executeQuery.getObject(2) + "\t");
System.out.print(executeQuery.getObject(3) + "\t");
System.out.print(executeQuery.getObject(4) + "\t");
System.out.print(executeQuery.getObject(5) + "\t");
System.out.println();
}
}
}
自定义事物链接处理栗子:
package com.zgrj.util;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class JDBCUtil {
//创建连接池对象
private static ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
//保存开启事务的连接
private static ThreadLocal<Connection> tl = new ThreadLocal<>();
/**
* 开启了事务
*/
public static void beginTrasaction() throws SQLException {
Connection connection = getConnection();
tl.set(connection);
connection.setAutoCommit(false);
}
/**
* 提交事务
* @throws SQLException
*/
public static void commit() throws SQLException {
Connection connection = tl.get();
connection.commit();
connection.close();
tl.remove();
}
/**
* 回滚事务
* @throws SQLException
*/
public static void rollback() throws SQLException {
Connection connection = tl.get();
connection.rollback();
connection.close();
tl.remove();
}
/**
* 获取连接
* @return
* @throws SQLException
*/
public static Connection getConnection() throws SQLException {
Connection connection = tl.get();
if(connection != null){
return connection;
}
return comboPooledDataSource.getConnection();
}
/**
* 回收资源
* @param conn
*/
public static void close(Connection conn) throws SQLException {
Connection connection = tl.get();
if(connection == null && conn != null)
conn.close();
if(conn != connection && conn != null) {
conn.close();
}
}
}
事物
事务的概念
事务是构成一个完整的逻辑单元的一条或者是多条sql语句.
在所谓的完整的逻辑单元中,每条sql语句是相互依赖的.而整个逻辑单元做为一个不可分割的整体.
如果单元中的某条sql语句一旦执行失败或者产生错误,那么整个单元的sql语句都将失败(回滚).
如果单元中的某条sql语句执行成功,那么整个单元的sql语句都要执行成功.
例:a向b转账的业务,需要如下sql语句:
update account set money=money-100 where name = ‘a’;
update account set money=money+100 where name=’b’;
上面这两条sql语句可以理解为一个整体,即一个完整的工作逻辑单元.因为少了哪句,该业务都会出现问题.
事务的特性(ACID)
原子性:指一个事务是一个不可分割的工作单元,事务中的操作要么都成功,要么都失败.
一致性:事务必须使数据库中的数据从一个一致性状态变换到另一个一致性状态.
隔离性:事务的隔离性是多个用户并发访问数据库时,数据库会为每一个用户开启事务,不能被其他用户的事务的操作所干扰,多个并发事务要相互隔离.
持久性:一个事务一旦提交,它对数据库中的数据的改变是永久的.
事务的隔离性所造成的影响
多个事务同时操作一个数据库的数据时,就会产生事务并发,会产生如下问题:
- 1.脏读:一个事务读取了另一个事务未提交的数据.
- 2.不可重复读:在同一个事务中,多次读取的数据不一致.(读取到了其他事务执行的update操作)
- 3.幻读(虚读):指的是一个事务读取到了另外一个事务在执行的insert语句.
数据库事务的隔离级别
- 1.read uncommitted:未提交读,是指脏读,不可重复读,幻读都有可能发生.
- 2.read committed:已提交读.可以避免脏读现象.但是不能避免不可重复读和幻读.
- 3.repeatable read:可重复读,可以避免脏读和不可重复读,但是不能避免幻读(mysql默认的隔离级别)
- 4.serializable:可串行化.脏读,不可重复读和幻读都可以避免.
注意:隔离级别越高,执行效率越低.数据越安全.
JDBC中事务的处理
手动开启Mysql中的事务
- mysql是支持事务的, 默认提交事务.即:每条sql语句就是一个独立的事务.所以需要我们手动开启事务.
- mysql控制事务的指令见:数据库知识的随笔那部分
JDBC的事务控制
连接对象提供了事务控制的方法,如下:
void setAutoCommit(false) 这个方法里面有三个参数 默认是true 手动开启是false //手动开启事务
void rollback( ) //手动回滚事务
void commit( ) //提交事务
ThreadLocal类的使用
/**
* 模拟ThreadLocal
*/
class ThreadLocal<T>{
private Map<Runnable,T>map = new HashMap<>();
public void set(T t){
map.put(Thread.currentThread(),t);
public T get(){
return map.get(Thread.currentThread());
}
public void remove(){
map.remove(Thread.currentThread())
}
}
}
使用了这个类的的工具类见上面栗子!😃
频频回头的人注定走不了远路。