事务:
概念:事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部失败。
数据库默认事务是自动提交的,也就是发一条sql语句他就执行一条,如果想多体哦啊sql语句放在一个事务中执行,则需要使用如下语句。
数据库开启事务命令:将所要使用的数据库语句放在下面的语句之间
Start transaction 开启事务
Rollback 回滚事务
Commit 提交事务
创建账户表:
1 create table account( 2 id int primary key auto_increment, 3 name varchar(40), 4 money float 5 )character set utf8 collate utf8_general_ci; 6 7 insert into account(name,money) values('aaa',1000); 8 insert into account(name,money) values('bbb',1000); 9 insert into account(name,money) values('ccc',1000);
使用事务:
当JDBC程序向数据库获得一个connection对象时,默认情况下这个connection对象会自动向数据库提交方式让多条sql在一个事务中执行,可使用下列语句。
JDBC控制事务语句:
1 Connection.setAutoCommit(false); start transaction 2 Connection.rollback(); rollback 3 Connention.commit(); commit
事务的四大特性:(ACID)
原子性(Atomicity):
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
一致性(Consistency):
事务前后数据的完整性必须保持一致。
隔离性(Isolation):
事务的隔离性是指多个用户并发访问数据库时,一个用户的事务不能被其他用户所干扰,多个并发事务之间数据要相互隔离。
持久性(Durability):
持久性是指一个事务一旦被提交,他对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。
事务的隔离级别:
多个线程开启各自十五操作数据库中数据时,数据库系统要负责隔离操作,以保证各个线程在获取数据时的准确性。否则会引发以下几个问题:
1.脏读:指一个事务读取了另外一个事务未提交的数据。
2.不可重复读:在一个事务内读取表中的某一行数据,多次读取结果不同。
二者的区别在于:脏读是读取前一事务未提交的脏数据,不可重复读是重新读取了前一事务已提交的数据。
3.虚读(幻读):是指在一个事务内读取到了别人的事务插入的数据,导致前后读取不一致。
数据库共定义了四种隔离级别:
1.Serializable:可避免脏读,不可重复读,虚读的情况发生。(串行化)
2.Repeatable read:可避免脏读,不可重复读的情况发生。(可重复读)
3.Read committed:可避免脏读情况发生(读已提交)
4.Read uncommitted:最低级别,以上情况均无法保证。(读未提交)
set transaction isolation level 设置事务隔离级别
select@@tx_isolation 查询当前事物的的隔离级别
因为考虑了数据库的执行效率所以将隔离级别设置为四种以便提高数据库的执行效率。
练习:演示各类问题的发生及隔离级别的避免方式。
当在Java程序中未设置隔离级别是系统会自动为MySQL设置repeatable的隔离级别。
1 1.演示脏读问题的发生
2
3 a窗口
4 set transaction isolation level read uncommitted;
5 start transaction ;
6 select * from account;
7 ------------发现a账户是1000元,转到b窗口
8 select * from account ;
9 ------------发现a账户是1100元,发生了脏读(这个事务读取到了别的事务未提交的数据)
10
11
12 b窗口
13 start transaction;
14 account set money=money+100 where name='aaa';
15 ----------事务在不提交的情况下,转到a窗口进行查询
16
17
18 2.避免脏读并演示不可重复读问题的发生
19 a窗口
20 set transaction isolation level read committed;
21 start transaction ;
22 select * from account;
23 ------------发现a账户是1000元,转到b窗口
24 select * from account ;
25 ------------发现a账户是1000元,这种read committed隔离级别 避免了脏读的发生。
26 -----------转到b窗口做提交
27 select * from account ;
28 ---------发现a账户是1100元,这时避免了脏读,但发生了不可重复读(指这个事务读取到了别的事务提交后的数据)。
29
30
31
32 b窗口
33 start transaction;
34 account set money=money+100 where name='aaa';
35 ----------事务在不提交的情况下,转到a窗口进行查询
36 commit;
37 ----------转到窗口进行查询。
38
39
40
41
42 3.避免脏读和不可重复读并演示虚读问题的发生
43 a窗口
44 set transaction isolation level repeatable read;
45 start transaction ;
46 select * from account;
47 -------发现A账户是1000元,并且表的总记录数是3条,转到B窗口
48 select * from account;
49 --------发现A账户是1000元,这说明repeatable这种隔离级别可以避免脏读。
50 -------转到B窗口
51 select * from account;
52 -------发现A账户还是1000,说明repeatable还可以避免不可重复读。
53 --------转到B窗口
54 select * from account;
55 -------发现表中可能会多出一条ddd的记录。这就发生了虚读,也就是在这个事务内读到了别的事务插入的数据(幻影数据)。
56
57
58
59 b窗口
60 start transaction;
61 update account set money=money+100 where name='aaa';
62 --------转到A窗口
63 commit;
64 ---------转到A窗口
65 start transaction;
66 insert into account (name,money) values('ddd','1000');
67 commit;
68 --------转到A窗口
使用数据库连接池优化程序性能:
若未使用数据连接池的缺点:用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗较大的资源,创建时间也较长。
编写数据库连接池:
编写连接池需要实现Java。sql.DataSource接口。DataSource接口中定义了两个重载的getConnection方法:
Connection getConnection()
Connection getConnection(String username String password)
实现DataSource接口,并实现连接池功能的步骤:
1.在DataSource构造函数中批量创建与数据库的连接,并把创建的连接加入LinkedList对象中。
2.实现getConnecction方法,让getConnection方法每次调用时,从LinkedList中取一个Connection返回给用户。
3.当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到LinkedList中,而不要把conn还给数据库。
4.Collection保证将自己返回到LinkedList中时此处编程的难点。
补充:在实际开发中,发现对象的方法满足不了开发需求时,有三种方式对其进行增强。
1.写一个子类,覆盖该方法,增强该方法。
当需要用子类方式增强时需要将所有信息导入到子类,若信息不好导则不能使用子类方式增强即当对象中信息很少时可以采用用子类方式来增强方法。
2.使用包装设计模式。
步骤过程:
1)定义一个类,实现与被增强相同的接口
2)在类中定义一个变量,记住被增强的对象
3)定义一个构造函数,接受被增强对象
4)覆盖想增强的方法
5)对于不想增强的方法,直接调用目标对象(被增强对象)的方法
3.动态代理:采用拦截的方式进行增强。(aop技术,面向切面编程)
开源数据库连接池(DataSource)
现在很多WEB服务器都提供了DataSoruce的实现,及连接池的实现,按其英文含义称之为数据源,数据源中到包含了数据库连接池的实现。
也有一些开源组织提供了数据源的独立:
DBCP数据库连接池(Tomcat内置的连接池)
C3P0数据库连接池
实际应用时不需要编写链接数据库代码,直接从数据源获得数据库的链接,程序员编程时也应尽量使用这些数据源的实现,以提升程序的数据库访问性能。
DBCB是Apache软件基金组织下的开源连接池实现,使用DBCP数据源,应用程序应在系统中增加两个jar文件:
Tomcat的连接池正式采用该连接池来实现的,改数据库连接池即可以与应用服务器整合使用,也可由应用程序独立使用。