1.什么是事务?
一件事情有n个组成单元,要不这n个组成单元同时成功,要不这n个单元同时失败。就是将n个组成单元放到一个事务中
2.mysql的事务
默认的事务:一条sql语句就是一个事务,默认就开启事务并提交事务
手动的事务:
1)显示的开启一个事务:start transaction
2)事务提交:commit代表从开启事务到事务提交,中间的所有sql都认为有效真正的更新数据库
3)事务的回滚:rollback代表事务的回滚,从开启事务到事务回滚,中间的所有的sql操作都认为无效数据库没有更新。
3.JDBC事务操作
默认是自动事务:
执行SQL语句:executeUpdate()每执行一次executeUpdate()方法,代表事务自动提交
通过jdbc的API手动事务:
开启事务:conn.setAutoCommit(false);
提交事务:conn.commit();
回滚事务:conn.rollback();
注意:控制事务的connection必须是同一个
执行sql的connection与开启事务的connection必须是同一个才能对事务进行控制
4.DBUtils事务操作
1)QueryRunner
有参构造:QueryRunner runner=new QueryRunner(DataSource dataSource);
有参构造将数据源(连接池)作为参数传入QueryRunner,他会从链接池中获得一个数据库链接资源池丛操作数据库,所以直接使用无Connection参数的方法即可操作数据库。
无参构造:QueryRunner runner=new QueryRunner();
无参的构造没有将数据源作为参数传入QueryRunner,那么我们在使用QueryRunner对象操作数据库时要使用有connection参数的方法。
5.事务的特性和隔离级别(面试)
1)事务的特性ACID
1.原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
2.一致性事务前后数据的完整性必须保持一致
3.隔离性多个事务,事务的隔离性是指多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间数据要相互隔离
4.持久性是指一个事务一旦被提交他对数据库中数据的改变就是持久性的,接下来即使数据库发送故障也不应该对其有任何影响
2)并发问题------有隔离性引起
1.脏读:B事务读取到了A事务尚无提交的数据-------要求B事务要读取A事务提交的数据
2.不可重复读:一个事务中两次读取的数据的内容不一致-----要求的是一个事务中多次读取数据是一致的
3.幻读/虚读:一个事务中,两次读取的数据的数量不一致-----要求在一个事务多次读取的数据的数量是一致的
3)事务的隔离级别
1.read uncommitted:读取尚未提交的数据---哪个问题都不能解决脏读
2.read commited:读取已经提交的数据-----解决脏读
3.repeatable read:重读读取:----可以解决脏读和不可重复读
4.serializable:串行化-----可以解决 脏读 不可重复读 虚读,相当于锁表
注意:mysql数据库默认的隔离级别:select @ @tx_isolation;
set session transaction isolate level read uncommitted;
总结:
mysql的事务控制:
开启事务:start transaction;
提交:commit;
回滚事务:rollback;
jdbc事务控制:
开启事务:conn.getAutoCommit(false);
提交事务:conn.commit();
回滚方法:conn.rollback();
DBUtils的事务控制:也是通过jdbc
ThreadLocal:可以实现的是通过线程绑定的方式传递参数
概念:
事务的特性:原子性,一致性,隔离性,持久性
并发问题:脏读,不可重读,虚读、幻读
解决并发问题:设置隔离级别
read uncommitted
read committed;
repeatable read(mysql默认)
serialazable
隔离级别性能:read uncommitted>read committed>repeatable read>serialazable
一件事情有n个组成单元,要不这n个组成单元同时成功,要不这n个单元同时失败。就是将n个组成单元放到一个事务中
2.mysql的事务
默认的事务:一条sql语句就是一个事务,默认就开启事务并提交事务
手动的事务:
1)显示的开启一个事务:start transaction
2)事务提交:commit代表从开启事务到事务提交,中间的所有sql都认为有效真正的更新数据库
3)事务的回滚:rollback代表事务的回滚,从开启事务到事务回滚,中间的所有的sql操作都认为无效数据库没有更新。
3.JDBC事务操作
默认是自动事务:
执行SQL语句:executeUpdate()每执行一次executeUpdate()方法,代表事务自动提交
通过jdbc的API手动事务:
开启事务:conn.setAutoCommit(false);
提交事务:conn.commit();
回滚事务:conn.rollback();
注意:控制事务的connection必须是同一个
执行sql的connection与开启事务的connection必须是同一个才能对事务进行控制
4.DBUtils事务操作
1)QueryRunner
有参构造:QueryRunner runner=new QueryRunner(DataSource dataSource);
有参构造将数据源(连接池)作为参数传入QueryRunner,他会从链接池中获得一个数据库链接资源池丛操作数据库,所以直接使用无Connection参数的方法即可操作数据库。
无参构造:QueryRunner runner=new QueryRunner();
无参的构造没有将数据源作为参数传入QueryRunner,那么我们在使用QueryRunner对象操作数据库时要使用有connection参数的方法。
5.事务的特性和隔离级别(面试)
1)事务的特性ACID
1.原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
2.一致性事务前后数据的完整性必须保持一致
3.隔离性多个事务,事务的隔离性是指多个用户并发访问数据库时,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间数据要相互隔离
4.持久性是指一个事务一旦被提交他对数据库中数据的改变就是持久性的,接下来即使数据库发送故障也不应该对其有任何影响
2)并发问题------有隔离性引起
1.脏读:B事务读取到了A事务尚无提交的数据-------要求B事务要读取A事务提交的数据
2.不可重复读:一个事务中两次读取的数据的内容不一致-----要求的是一个事务中多次读取数据是一致的
3.幻读/虚读:一个事务中,两次读取的数据的数量不一致-----要求在一个事务多次读取的数据的数量是一致的
3)事务的隔离级别
1.read uncommitted:读取尚未提交的数据---哪个问题都不能解决脏读
2.read commited:读取已经提交的数据-----解决脏读
3.repeatable read:重读读取:----可以解决脏读和不可重复读
4.serializable:串行化-----可以解决 脏读 不可重复读 虚读,相当于锁表
注意:mysql数据库默认的隔离级别:select @ @tx_isolation;
set session transaction isolate level read uncommitted;
总结:
mysql的事务控制:
开启事务:start transaction;
提交:commit;
回滚事务:rollback;
jdbc事务控制:
开启事务:conn.getAutoCommit(false);
提交事务:conn.commit();
回滚方法:conn.rollback();
DBUtils的事务控制:也是通过jdbc
ThreadLocal:可以实现的是通过线程绑定的方式传递参数
概念:
事务的特性:原子性,一致性,隔离性,持久性
并发问题:脏读,不可重读,虚读、幻读
解决并发问题:设置隔离级别
read uncommitted
read committed;
repeatable read(mysql默认)
serialazable
隔离级别性能:read uncommitted>read committed>repeatable read>serialazable
安全性:反过来
index.jsp
<body>
<h1>转账页面</h1>
<form action="${pageContext.request.contextPath }/accountServlet" method="post">
<table border="1" width="400">
<tr>
<td>付款人:</td>
<td><input type="text" name="from"/></td>
</tr>
<tr>
<td>收款人:</td>
<td><input type="text" name="to"/></td>
</tr>
<tr>
<td>转账金额:</td>
<td><input type="text" name="money"/></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="转账"/></td>
</tr>
</table>
</form>
</body>
AccountServlet.java
public class AccountServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public AccountServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/**
* 接收数据
* 封装数据
* 调用业务层
* 页面跳转做出响应
*/
response.getWriter().write("hello");
request.setCharacterEncoding("utf-8");
//接收数据
String from=request.getParameter("from");
String to=request.getParameter("to");
double money=Double.parseDouble(request.getParameter("money"));
//调用业务层
AccountService accountService=new AccountService();
accountService.transfer(from,to,money);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
service层
public class AccountService {
/**
* 业务层转账的方法
* 付款人
* 收款人
* 转账金额
*/
public void transfer(String from,String to,double money){
Connection conn=null;
try{
//获得链接
String url="jdbc:mysql://localhost:3306/web";
String userName="root";
String pwd="";
try{
conn=DriverManager.getConnection(url,userName,pwd);
if(conn!=null){
}
}catch(Exception e){
e.printStackTrace();
}
//conn.JdbcUtils.getConnection();
//开启事务
conn.setAutoCommit(false);
//调用DAO
AccountDao accountDao=new AccountDao();
accountDao.outMoney(conn,from,money);
accountDao.inMoney(conn,to,money);
conn.commit();
}catch(SQLException e){
try{
if(conn!=null){
conn.rollback();
}
}catch(Exception e2){}
throw new RuntimeException(e);
//e.printStackTrace();
}finally{
}
}
}
DAO层
public class AccountDao {
public void outMoney(Connection conn,String outUser,int money) throws SQLException{
PreparedStatement psmt=null;
ResultSet rs=null;
try{
String sql="update account set money=money-? where username=?";
psmt=conn.prepareStatement(sql);
psmt.setInt(1, money);
psmt.setString(2, outUser);
int r=psmt.executeUpdate();
System.out.println(r);
}catch(Exception e){
throw new RuntimeException(e);
}finally{
psmt.close();
rs.close();
}
}
public void inMoney(Connection conn,String inUser,int money) throws SQLException{
PreparedStatement psmt=null;
ResultSet rs=null;
try{
String sql="update account set money=money+? where username=?";
psmt=conn.prepareStatement(sql);
psmt.setInt(1, money);
psmt.setString(2, inUser);
int r=psmt.executeUpdate();
System.out.println(r);
}catch(Exception e){
throw new RuntimeException(e);
}finally{
psmt.close();
rs.close();
}
}
}