事务+事务的四大特性+隔离性的具体分析+数据库连接池

来源:互联网 发布:在淘宝怎么开旗舰店 编辑:程序博客网 时间:2024/05/17 23:18
一、事务
1.事务的概念:事务是指逻辑上的一组操作,这组操作要么同时完成要么同时不完成。参考转账操作。
2.如果你自己不去控制事务,数据库默认一条sql语句就处在自己单独的事务当中。
3.也可以使用命令去开启一个事务:
start transaction;--开启事务,这条语句之后的sql语句将处在一个事务当中,这些sql语句并不会立即执行
Commit--提交事务,一旦提交事务,事务中的所有sql语句才会执行。
Rollback -- 回滚事务,将之前所有的sql取消。

conn.setAutoCommit(false);
conn.commit();
conn.rollback();
conn.setSavePoint();
conn.rollback(sp);

4.事务的四大特性ACID
~原子性:事务的一组操作是原子的不可再分割的,这组操作要么同时完成要么同时不完成。
~一致性: 事务在执行前后数据的完整性保持不变。数据库在某个状态下符合所有的完整性约束的状态叫做数据库具有完整性。在解散一个部门时应该同时处理员工表中的员工保证这个事务结束后,仍然保证所有的员工能找到对应的部门,满足外键约束。
~隔离性:当多个事务同时操作一个数据库时,可能存在并发问题,此时应保证各个事务要进行隔离,事务之间不能互相干扰。
~持久性:持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,不能再回滚。

5.事务的隔离性导致的问题(所有的问题都是在某些情况下才会导致问题)
~脏读:一个事务读取到了另一个事务未提交的数据。 
1 | a    |  1000
  2 | b    |  1000
 
  b--->a
  start transaction;
  update account set money=money-100 where name='b';
update account set money=money+100 where name='a';
rollback;


select * from account where name = 'a';1000 1000

~不可重复读:在一个事务内读取表中的某一行数据,多次读取结果不同.
start transaction:
活期存款:1000
定期存款:1000
固定资产: 2000
--------------
开启事务
取走获取存款1000
提交事务
--------------
总资产:3000

~幻读(虚读):一个事务读取到了另一个事务插入的数据(已提交)
a 2000
b 2000
c 2000
start transaction;
select sum(money) from account;6000
--------------
开启事务
创建一个账户并存入1000块钱
提交了事务
--------------
select count(*)from account;4
avgMoney = allMoney/count;6000/4=1500

6.数据库的隔离级别
~Read uncommitted:如果将数据库设定为此隔离级别,数据库将会有脏读、不可重复度、幻读的问题。
~Read committed:如果将数据库设定为此隔离级别,数据库可以防止脏读,但有不可重复度、幻读的问题。
~Repeatable read: 如果将数据库设定为此隔离级别,数据库可以防止脏读、不可重复度,但是不能防止幻读。
~Serializable:将数据库串行化,可以避免脏读、不可重复读、幻读。

安全性来说:Serializable>Repeatable read>Read committed>Read uncommitted
效率来说:Serializable<Repeatable read<Read committed<Read uncommitted
通常来说,一般的应用都会选择Repeatable read或Read committed作为数据库隔离级别来使用。
mysql默认的数据库隔离级别为:REPEATABLE-READ

如何查询当前数据库的隔离级别?select @@tx_isolation;
如何设置当前数据库的隔离级别?set [global/session] transaction isolation level ...;
~此种方式设置的隔离级别只对当前连接起作用。
set transaction isolation level read uncommitted;
set session transaction isolation level read uncommitted;
~此种方式设置的隔离级别是设置数据库默认的隔离级别
set global transaction isolation level read uncommitted;

7.做实验,演示脏读、不可重复度、幻读
~演示脏读
~演示不可重复度
~演示幻读:幻读有可能发生有可能不发生,但是一旦发生就可能造成危害。
~演示Serializable:基于锁机制运行

8.锁机制:
共享锁:共享锁和共享锁可以共存。
排他锁:排他锁和所有锁都不能共存。
在非串行化下,所有的查询都不加锁,所有的修改操作都会加排他锁。
在串行化下,所有的查询都加共享锁,所有的修改都加排他锁。
死锁

9.更新丢失
如果多个线程操作,基于同一个查询结构对表中的记录进行修改,那么后修改的记录将会覆盖前面修改的记录,前面的修改就丢失掉了,这就叫做更新丢失。
Serializable可以防止更新丢失问题的发生。其他的三个隔离级别都有可能发生更新丢失问题。
Serializable虽然可以防止更新丢失,但是效率太低,通常数据库不会用这个隔离级别,所以我们需要其他的机制来防止更新丢失:

乐观锁和悲观锁不是数据库中真正存在的锁,只是人们在解决更新丢失时的不同的解决方案,体现的是人们看待事务的态度。
悲观锁:
隔离级别不设置为Serializable,防止效率过低。
在查询时手动加上排他锁。
如果数据库中的数据查询比较多而更新比较少的话,悲观锁将会导致效率低下。

乐观锁:
在表中增加一个version字段,在更新数据库记录是将version加一,从而在修改数据时通过检查版本号是否改变判断出当前更新基于的查询是否已经是过时的版本。
如果数据库中数据的修改比较多,更新失败的次数会比较多,程序需要多次重复执行更新操作。





二、数据库连接池
1.连接池概念:
2.自己写一个连接池:
使自己的连接池在conn调用close方法是可以将连接直接返回池中:
修改一个类中某个方法的功能:
继承
装饰设计模式模式
动态代理

3.开源数据库连接池:
(1)DBCP
BasicDataSource dataSource = new BasicDataSource();
String path = this.getClass().getClassLoader().getResource("dbcp.properties").getPath();
Properties prop = new Properties();
prop.load(new FileInputStream(path));
DataSource dataSource = BasicDataSourceFactory.createDataSource(prop);
配置文件属性:
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbc
username=root
password=

#<!-- 初始化连接 -->
initialSize=10

#最大连接数量
maxActive=50

#<!-- 最大空闲连接 -->
maxIdle=20

#<!-- 最小空闲连接 -->
minIdle=5

#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000

(2)C3P0
ComboPooledDataSource dataSource = new ComboPooledDataSource();
ComboPooledDataSource dataSource = new ComboPooledDataSource("mySoruce");
<?xml version="1.0"?>
<c3p0-config>
 <default-config>
<property  name="driverClass">com.mysql.jdbc.Driver</property >
<property name="jdbcUrl">jdbc:mysql:///Day12</property >
<property name="user">root</property>
<property name="password">root</property>
 </default-config>

 <!-- This app is massive! -->
 <named-config name="mySoruce"> 
  <property  name="driverClass">com.mysql.jdbc.Driver</property >
<property name="jdbcUrl">jdbc:mysql:///Day12</property >
<property name="user">root</property>
<property name="password">root</property>
 </named-config>
</c3p0-config>

driverClass
jdbcUrl
user
password
acquireIncrement:当连接池中已经没有连接时,连接池自动获取连接时一次获取的连接个数。
initialPoolSize:连接池初始化时,获取连接的个数。
maxPoolSize:连接池可以保有的最大的连接的数量。
maxIdleTime:当连接空闲多久时释放连接。如果该时间值设置问为0,表示从不释放连接。
minPoolSize:连接池应该保有的最小的连接的数量。


4.tomcat内置的数据源:tomcat内置了DBCP数据源
<1>在tomcat的安装目录下的lib目录下导入数据库驱动包
<2>在Context中配置数据源,有五个位置可以配置,参考tomcat文档
~在conf/context.xml爸爸Context中配置,这个配置将被tomcat的所有web应用共享
In the $CATALINA_BASE/conf/context.xml file: the Context element information will be loaded by all webapps.
~在conf/Catalina/localhost/context.xml,这个配置将被当前虚拟主机所共享
In the $CATALINA_BASE/conf/[enginename]/[hostname]/context.xml.default file: the Context element information will be loaded by all webapps of that host.
~在conf/Catalina/localhost/XXXXXX.xml,这是配置web应用的对外访问路径,这个配置只对当前web应用起作用
In individual files (with a ".xml" extension) in the $CATALINA_BASE/conf/[enginename]/[hostname]/ directory. The name of the file (less the .xml extension) will be used as the context path. Multi-level context paths may be defined using #, e.g. foo#bar.xml for a context path of /foo/bar. The default web application may be defined by using a file called ROOT.xml.
~在web应用个的META-INF目录下创建context.xml这个配置只对当前web应用起作用
Only if a context file does not exist for the application in the $CATALINA_BASE/conf/[enginename]/[hostname]/, in an individual file at /META-INF/context.xml inside the application files. If the web application is packaged as a WAR then /META-INF/context.xml will be copied to $CATALINA_BASE/conf/[enginename]/[hostname]/ and renamed to match the application's context path. Once this file exists, it will not be replaced if a new WAR with a newer /META-INF/context.xml is placed in the host's appBase.
~在conf/servler.xml的Host标签下配置Context标签
Inside a Host element in the main conf/server.xml.
<3>在Cotext中配置:
 <Resource name="mySource"  ---在数据源创建好以后绑定到jndi容器中时使用的名字
            auth="Container" 
            type="javax.sql.DataSource" ---当前对象的类型,默认就是数据源
            username="root"  --- 数据库用户名
            password="root"  --- 数据库密码
            driverClassName="com.mysql.jdbc.Driver" ---数据库驱动名
            url="jdbc:mysql:///day12" --- 数据库连接信息
            maxActive="8" --- 最大连接数
            maxIdle="4"/> --- 最大空闲连接数
   <4>在程序中获取数据源:
  Context context = new InitialContext();
Context envCtx = (Context)context.lookup("java:comp/env"); 
DataSource datasource = (DataSource) envCtx.lookup("mySource");
0 0