Java实战之04JavaWeb-05事务和连接池
一、事务部分
1.事务的简介
做一件事情,这个一件事情中有多个组成单元,这个多个组成单元要不同时成功,要不同时失败。A账户转给B账户钱,将A账户转出钱的操作与B账户转入钱的操作绑定到一个事务中,要不这两个动作同时成功,代表这次转账成功,要不就两个动作同时失败,代表这次转账失败。
2.mysql的事务控制
mysql默认事务是自动提交的,一条sql是一个事务
手动开启事务:start transaction
当手动开启事务后,数据库默认的事务的自动提交暂时失效
提交事务:commit
提交事务到开启事务之间的所有的sql语句都生效
回滚事务:rollback
从回滚事务到开启事务之间的所有的sql操作都无效
3.jdbc的API的事务控制
通过Connection对象可以控制事务
jdbc中想控制事务其实是控制jdbc的更新数据库的API方法---executeUpdate
开启事务:connection.setAutoCommit(false);
提交事务:connection.commit();
回滚事务:connection.rollback();
4.事务的四大特性ACID
原子性:数据库的操作的最小的单位就是事务
一致性:一个事务中的多个操作的结果数据是一致的,同时成功和同时失败
隔离性:多个事务之间的操作互不影响
持久性:当一个事务提交后,更新操作才持久化到磁盘上
在不考虑隔离性的前提下会产生哪些影响?
模拟两个事务A事务 B事务
脏读:B事务读到了A事务尚未提交的事务
不可重复读:A事务中两次读取的数据的内容不一致
虚读/幻读:A事务中两次读取的数据的数量不一致
5.事务的隔离级别
通过设置数据库的隔离级别 解决上述的问题:
read uncommitted:读取尚未提交的事务,什么都不能解决
read committed:读取已经提交的内容,可以解决脏读
repeatable read:重复读,可以解决脏读和不可重复读
serializable:串行化,可以解决所有
数据库默认的隔离级别
mysql的默认隔离级别:repeatable read
oracle的默认的隔离级别:read committed
查询数据库的隔离级别:select @@tx_isolation
手动的修改数据库默认的隔离级别:
set session transaction isolation level 设置事务隔离级别
模拟脏读步骤:
1)开启两个客户端 分别进入数据库
2)设置两个客户端数据库隔离级别为read uncommitted
3)两个客户端分别开启事务
4)A客户端修改数据但是尚未提交
5)B客户端查询数据 发现数据已经修改
6)A客户端回滚
隔离级别性能问题:serializable<repeatable read<read committed<read uncommitted
隔离级别安全问题:serializable>repeatable read>read committed>read uncommitted
注意:事务控制必须在service层
ThreadLocal:代表是专门存放当前线程的数据的map
获取当前线程的数据:get();
设置当前线程上绑定的数据:set(value)
删除当前线程上绑定的数据:remove()
二、连接池部分
1.连接池的简介
(1)什么是连接池
存放数据库连接资源(Connection)的池子
(2)为什么需要连接池
1)节约连接资源 提高程序的性能
2)防止数据库服务器连接资源溢出
(3)连接池内部的原理
1)连接池一创建就初始化一些Connection资源
2)当使用Connection时不是创建而是从池子中获取一个资源
3)当资源使用完毕 不是将该资源销毁 而是将资源在归还给池子
(4)自定义连接池
1 public class MyDataSource { 2 //1、创建一个池子 3 private static LinkedList<Connection> datasource = new LinkedList<Connection>(); 4 //2、在创建DataSource时 就为池子初始化一些连接资源 5 public MyDataSource(int count){ 6 for(int i=0;i<count;i++){ 7 try { 8 //conn 是mysql驱动包提供的对象 9 Connection conn = JDBCUtils.getConnection(); 10 //怎样对一个对象中的方法进行加强 11 //BufferedReader reader = new BufferedReader(new FileReader("")); 12 ConnectionWrapper wrapper = new ConnectionWrapper(conn); 13 //在将connnection资源放置到池子中之前 对conn进行一些加强(主要加强是close方法) 14 datasource.add(wrapper); 15 } catch (Exception e) { 16 e.printStackTrace(); 17 } 18 } 19 } 20 //获取connection的方法 21 public static Connection getConnection(){ 22 return datasource.removeFirst(); 23 } 24 //将使用完毕的资源放回池子中 25 public static void giveBack(Connection conn){ 26 System.out.println("归还前的数量:"+datasource.size()); 27 datasource.addLast(conn); 28 System.out.println("归还后的数量:"+datasource.size()); 29 } 30 public static void main(String[] args) throws SQLException { 31 MyDataSource dataSource = new MyDataSource(10); 32 Connection conn = dataSource.getConnection(); 33 System.out.println(conn); 34 //调用PreparedStatement对象 35 PreparedStatement pstmt = conn.prepareStatement("select * from account"); 36 System.out.println(pstmt); 37 ///dataSource.giveBack(conn); 38 //问题:想要做的是当conn在调用close方法时 不是销毁 而是将conn放回池子中 39 conn.close(); 40 } 41 }
装饰者模式:
1)加强的类与被加强的类必须实现同一个接口
2)要将被加强的类作为构造器的参数传入
3)要加强的方法重写逻辑,不需要加强的方法调用被加强的
2.常用的开源的连接池技术
DBCP:Apache基金会的开源的连接池技术 Commons项目中子项目
C3P0:开源的连接池技术
(1)DBCP连接池技术
下载jar包
导入jar包
1 public class DBCPDemo { 2 @Test 3 public void test1() throws SQLException{ 4 //1、获得一个连接池 5 BasicDataSource dataSource = new BasicDataSource(); 6 //设置数据库的信息 7 dataSource.setDriverClassName("com.mysql.jdbc.Driver"); 8 dataSource.setUrl("jdbc:mysql:///database"); 9 dataSource.setUsername("root"); 10 dataSource.setPassword("root"); 11 //2、获得一个连接资源 12 Connection conn = dataSource.getConnection(); 13 System.out.println(conn); 14 //3、将资源归还 15 conn.close(); 16 } 17 @Test 18 public void test2() throws Exception{ 19 InputStream in = DBCPDemo.class.getClassLoader().getResourceAsStream("dbcp.properties"); 20 Properties pro = new Properties(); 21 pro.load(in); 22 DataSource dataSource = BasicDataSourceFactory.createDataSource(pro); 23 Connection conn = dataSource.getConnection(); 24 System.out.println(conn); 25 conn.close(); 26 } 27 }
(2)C3P0连接池
下载jar包
导入jar包
1 public class C3P0Demo { 2 @Test 3 public void test1() throws Exception{ 4 //创建连接池 5 ComboPooledDataSource dataSource = new ComboPooledDataSource(); 6 //设置四个基本参数 7 dataSource.setDriverClass("com.mysql.jdbc.Driver"); 8 dataSource.setJdbcUrl("jdbc:mysql:///database"); 9 dataSource.setUser("root"); 10 dataSource.setPassword("root"); 11 //获取连接 12 Connection conn = dataSource.getConnection(); 13 System.out.println(conn); 14 conn.close(); 15 } 16 @Test 17 public void test2() throws SQLException{ 18 //创建连接池 19 //ComboPooledDataSource dataSource = new ComboPooledDataSource("haohao"); 20 ComboPooledDataSource dataSource = new ComboPooledDataSource(); 21 Connection conn = dataSource.getConnection(); 22 System.out.println(conn); 23 conn.close(); 24 } 25 }