MySQL事务
事务是指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部不成功。
如果有两条sql语句执行,要么两条sql语句都执行成功,要么两头都不执行。
例:A给B转账
1 | update account set money=money-100 where name='a'; |
数据库开启事务命令
- mysql支持事务
- mysql默认自动提交事务,每条语句都处在单独的事务中。
- 事务操作
- start transaction 开启事务
- Rollback 回滚事务
- commit 提交事务
JDBC使用事务
当jdbc程序向数据库获得一个Connection对象时,默认情况下这个Connection对象会自动向数据提交在它上面发送的sql语句。若想关闭这个默认提交方式,让多条sql在同一个事物中执行,可以用connection对象中一些方法来实现上面提到的三个事务操作。
- Connection.setAutoCommit(false); start transaction
- Connection.rollback(); rollback
- Connection.commit(); commit
1 | public class Demo01 { |
事物的特性
原子性:指事物是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
一致性:事务必须使数据库从一个一致性状态变换成另一个一致性状态。转帐前和转账后的总金额不变。
隔离性:事物的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事物,不能被其他食物的操作数据所干扰,多个并发事物之间要相互隔离。
持久性:指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。
事物的隔离级别
数据库并发操作可能会引起下面的问题:
脏读:指一个事务读取了另外一个事务未提交的数据。
不可重复读:在一个事务内读取表中的某一行数据,多次读取结果不同。一个事务取到了另一个事务提交后的数据。(update)
虚读(幻读):指在一个事务内读取到了别的事物插入的数据,导致前后读取不一致。(insert)
数据库通过设置事物的隔离级别来防止以上情况的发生:
READ UNCOMMITED[读未提交]:上述三种情况都有可能发生。
READ COMMITED[读已提交]:可以避免脏读。(oracle默认)
REPEATABLE READ[可重复度]:避免脏读,不可重复度。虚读有可能发生。(MySQL默认)
SERIALIZABLE:避免上面三种情况。不能多线程操作。
数据越安全,性能越低。
MySQL中:
- 查看当前事务隔离级别:SELECT @@TX_ISOLATION;
- 更改当前的事务隔离级别:SET TRANSACTION ISOLATION LEVEL 上面四个级别之一。
- 设置隔离级别必须在事务之前。
隔离级别演示
通过两个终端访问数据库来模拟多线程。
数据库连接池
当连接数据库的连接数很多时,为每一个用户单独创建连接就变得效率低下了。所以我们有了连接池,在连接池中事先放好很多连接,用户请求连接数据库时,从连接池中拿到连接,用完再放回连接池。
解决了建立数据库连接耗费资源和时间很多的问题,提高性能。
常用的数据库连接池
DBCP(Database Connection Pool)数据库连接池,是java数据库连接池的一种,由Apache开发,通过数据库连接池,可以让程序自动管理数据库连接的释放和断开。
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3和JDBC2的规范,目前使用它的开源项目有Hibernate和Spring。
使用DBCP连接数据库
导入commons-DBCP和commons-pool两个包。
使用db.properties配置数据库和连接池的设置。
使用C3P0连接数据库
添加C3P0.jar包。
编写配置文件c3p0-config.xml,放在classpath或classes目录中。
JNDI
Java Naming and Directory interface是一个应用程序设计的API。为开发人员提供查找和访问各种命名和服务的通用、统一的接口。类似于JDBC都是构建在抽象层上。现在JNDI已经成为了J2EE的标准之一,所有的J2EE容器都必须提供一个JNDI服务。
Tomcat中配置JNDI数据源
开发JavaWeb应用,必须使用一个JavaWeb服务器,JavaWeb服务器都内置数据源。这种配置就是JNDI。
Tomcat中内置了数据源DBCP,使用数据源只需要配置服务器即可。
配置数据源的步骤
拷贝数据库连接驱动的jar到tomcat的lib目录下。
- 出现java.lang.AbstractMethodError请使用更高版本的数据库驱动连接。
配置数据源的XML文件
如果把配置信息写在tomcat下conf目录的context.xml中,那么多有应用都能使用此数据源。
如果是配置在应用的META-INF中创建context.xml,编写数据源,那么是由当前应用可以使用。
1
2
3
4
5
6
7
8
9
10
11
12
13
<Context>
<Resource name="jdbc/db1"
auth="Container"
type="javax.sql.DataSource"
username="root"
password="123456"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql//localhost:3306/db1"
maxTotal="8"
maxIdle="4"
/>
</Context>
使用连接池
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41public class DBUtils {
private static DataSource ds;
static {
try {
// 读取数据源context.xml
Context context = new InitialContext();
ds = (DataSource)context.lookup("java:comp/env/jdbc/dbdemo");
} catch (NamingException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
public static void close(Connection conn, ResultSet rs, Statement stmt){
if(rs!=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt!=null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
多个数据源
一个项目中可能要访问多个数据库。
声明多个<Resource/>
即可。
数据源:可以理解为数据库连接池。有3中实现方式:
- DBCP。
- C3P0,一般与hibernate一起使用。
- JNDI,tomcat内置的dbcp。