1、事务
事务的四大特性:
1)原子性: 事务中所有操作都是不可分割的原子单位。
2)一致性: 事务执行后,数据库连接状态和业务数据规则保持一致。
3)隔离性: 在并发操作中,不同数据之间应该隔离开。
4)持久性: (备份)
事务一旦提交,事务中所有数据操作都必须持久化到数据库中,
就算数据库突然崩溃,也能在重启后回复数据。
mysql中的事务
将不可分割的sql语句设为事务。
背景:在默认情况下,MySQL每执行一条SQL语句,都是一个单独的事务。
如果需要在一个事务中包含多条SQL语句,那么需要开启事务和结束事务。
开启事务:1)start transaction;
结束事务:1)commit //结束事务
2)rollback。 //回滚事务,重新开始操作,一般用于操作失败时。
开启事务 -> 关闭事务
jdbc中的事务
jdbc通过Connection处理事务
同一事务中所有的操作,都在使用同一个Connection对象!
Connection与事务相关的三个方法:
setAutoCommit(boolean):设置是否为自动提交事务,
true(默认):表示自动提交,也就是每条执行的SQL语句都是一个单独的事务。
false:开启事务。con.setAutoCommit(false)。
commit():结束事务。 con.commit();
rollback():回滚事务。 con.rollback();
jdbc处理事务的代码格式:
try {
con.setAutoCommit(false);//开启事务…
….
…
con.commit();//try的最后提交事务
} catch() {
con.rollback();//回滚事务
}
2、事务隔离级别:
1.并发事务问题:包括三种读问题,两种更新问题。
事务的并发读问题:
1)脏读:读到另一个事务未提交数据
2)不可重复读:对同一记录的两次读取不一致。因为另一事务对该记录做了修改
3)幻读(虚读):对同一表两次查询不一致。
四大隔离级别:
防止三种并发读问题。
1)SERIALIZABLE(串行化)
不会出现任何并发问题。
性能最差
2)REPEATABLE READ(可重复读)
防止脏读和不可重复读。
mysql默认隔离级别
3)READ COMMITTED(读已提交数据)oracle
防止脏读
oracle默认隔离级别
4)READ UNCOMMITTED(读未提交数据)
未做隔离,任何事务并发问题都可能出现。
性能最好
性能:4 > 3 > 2 > 1
查看及设置隔离级别
mysql查看数据库隔离级别语句
SELECT @@TX_ISOLATION
set transaction isolationlevel [4选一]
JDBC设置隔离级别语句
con. setTransactionIsolation(int level)
参数可选值如下:
Connection.TRANSACTION_READ_UNCOMMITTED;
Connection.TRANSACTION_READ_COMMITTED;
Connection.TRANSACTION_REPEATABLE_READ;
Connection.TRANSACTION_SERIALIZABLE。
3、事务演示
public class Transaction {
/**
* 转账方法
*
* @param from
* 金钱来源
* @param to
* 金钱去处
* @param money
* 交易金额
* @throws Exception
*/
public void transaction(String from, String to, double money) {
// jdbc对事务操作需要使用Connection
Connection con = null;
try {
con = JdbcUtils.getConnection();
// 开启事务
con.setAutoCommit(false);
// 创建操作对象 AccountDao
AccountDao dao = new AccountDao();
// 转账操作
dao.updateBalance(con, from, -money); // 给from减去相应金额
dao.updateBalance(con, to, money); // 给to加上相应金额
// 提交事务
con.commit();
con.close();
} catch (Exception e) {
// 回滚事务
try {
con.rollback();
con.close();
} catch (SQLException e1) {
}
throw new RuntimeException(e);
}
}
//测试事务
@Test
public void fun1() {
transaction("zs", "ls", 100);
}
}
public class AccountDao {
/**
* 在sql处修改指定用户的余额
* @param name
* @param balance
* @throws Exception
*/
public void updateBalance(Connection con,String name, double balance) throws Exception{
PreparedStatement pstmt = null;
try{
//给pstmt设置sql模板
String sql = "update account set balance=balance+? where name=?";
pstmt = con.prepareStatement(sql);
//对参数设值
pstmt.setDouble(1,balance);
pstmt.setString(2, name);
//执行
pstmt.executeUpdate();
}catch(Exception e){
throw new RuntimeException(e);
}
}
}
4、数据库连接池:
作用:用池来管理 Connection,达到重复使用Connection的目的。
实现接口
连接池必须实现:javax.sql.DataSource接口!
池参数(所有池参数都有默认值):
初始大小:10个
最小空闲连接数:3个
增量:一次创建的最小单位(5个)
最大空闲连接数:12个
最大连接数:20个
最大的等待时间:1000毫秒 超时间将异常。
四大连接参数
连接池也是使用四大连接参数来完成创建连接对象!
连接池返回的Connection对象。
调用它的close()不是关闭,而是把连接归还给池!
DBCP连接池:
/*
* DBCP连接池
*/
public class Demo1 {
@Test
public void fun1() throws SQLException {
/*
* 1. 创建连接池对象
* 2. 配置四大参数
* 3. 配置池参数
* 4. 得到连接对象
*/
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/mydb3");
dataSource.setUsername("root");
dataSource.setPassword("123");
//设置连接池初始化参数
dataSource.setMaxActive(20);
dataSource.setMinIdle(3);
dataSource.setMaxWait(1000);
//得到连接
Connection con = dataSource.getConnection();
Connection con1 = new MyConnection(con);
System.out.println(con1.getClass().getName());
/**
* 连接池内部使用四大参数创建了连接对象!即mysql驱动提供的Connection
* 连接池使用mysql的连接对象进行了装饰,只对close()方法进行了增强!
* 装饰之后的Connection的close()方法,用来把当前连接归还给池!
*/
con1.close();//把连接归还给池!
}
}
C3P0连接池:
开源免费。
使用连接池:
先导包。
c3p0-0.9.2-pre1.jar
mchange-commons-0.2.jar
mysql-connector-java-5.1.28-bin.jar
配置方法一:手动配置
// 1. 创建连接池对象
// ComboPooledDataSource ds = new ComboPooledDataSource();
// 2. 配置四大参数
// 3. 配置池参数
// 4. 得到连接对象
配置方法二:配置文件配置
配置文件要求:
文件名称:必须叫c3p0-config.xml
文件位置:必须在src下
使用时直接连接即可
eg:
<?xml version="1.0" encoding="UTF-8" ?>
<c3p0-config>
<default-config>
//连接四大参数配置
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="user">root</property>
<property name="password">123456</property>
//池参数配置
<property name="acquireIncrement">3</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">2</property>
<property name="maxPoolSize">10</property>
</default-config>
</c3p0-config>
一个配置文件中可以存在提供多种配置
使用其他配置时需传参 配置名
ComboPooledDataSource ds = new ComboPooledDataSource("orcale-config");
5、Tomcat配置JNDI资源JNDI
JNDI(Java Naming and Directory Interface),Java命名和目录接口。
目的:通过统一方式来获取配置的资源。
做法:在Tomcat服务器上配置连接池
1)在localhost下新建 项目名.xml
E:\apache-tomcat-7.0.88\conf\Catalina\localhost\day18.xml
注:此文件用完即删。 否则在项目关闭后,tomcat服务器将会抛出异常,不能正常使用
2)获取资源: 在Servlet下获取
1)在localhost下新建 项目名.xml
<?xml version="1.0" encoding="UTF-8" ?>
<Context>
<!--
name:指定资源的名称
factory:资源由谁来负责创建
type:资源的类型
其他的东西都是资源的参数
-->
<Resource name="jdbc/dataSource"
factory="org.apache.naming.factory.BeanFactory"
type="com.mchange.v2.c3p0.ComboPooledDataSource"
jdbcUrl="jdbc:mysql://localhost:3306/mydb1"
driverClass="com.mysql.jdbc.Driver"
user="root"
password="123456"
acquireIncrement="5"
initialPoolSize="10"
/>
</Context>
2)获取资源 –> 在Servlet下获取:
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/*
* 1. 创建JNDI的上下文对象
*/
try {
Context cxt = new InitialContext();
// 2查询出入口
// Context envContext = (Context)cxt.lookup("java:comp/env");
// 3. 再进行二次查询,找到我们的资源
// 使用的是名称与<Resource>元素的name对应
// DataSource dataSource = (DataSource)envContext.lookup("jdbc/dataSource");
DataSource dataSource = (DataSource)cxt.lookup("java:comp/env/jdbc/dataSource");
//得到连接
Connection con = dataSource.getConnection();
System.out.println(con);
con.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}