事务概述
一件事情有n个组成单元 要不这n个组成单元同时成功 要不n个单元就同时失败
就是将n个组成单元放到一个事务中
MySQL的事务
默认的事务:一条sql语句就是一个事务 默认就开启事务并提交事务
手动事务:
1)显示的开启一个事务:start transaction
2)事务提交:commit代表从开启事务到事务提交 中间的所有的sql都认为有效 真正的更新数据库
3)事务的回滚:rollback 代表事务的回滚 从开启事务到事务回滚 中间的所有的 sql操作都认为无效数据库没有被更新
JDBC事务操作
默认是自动事务:
执行sql语句:executeUpdate() ---- 每执行一次executeUpdate方法 代表 事务自动提交
通过jdbc的API手动事务:
开启事务:conn.setAutoComnmit(false);
提交事务:conn.commit();
回滚事务:conn.rollback();
注意:控制事务的connnection必须是同一个
执行sql的connection与开启事务的connnection必须是同一个才能对事务进行控制
例子:
package com.oracle.demo01; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; public class JDBCDemo { public static void main(String[] args) { Connection conn=null; try { //1.注册驱动 Class.forName("com.mysql.jdbc.Driver"); //2.获得链接 String url="jdbc:mysql://localhost:3306/bank?characterEncoding=utf8"; String user="root"; String password="123456"; conn=DriverManager.getConnection(url, user, password); //开启事务(手动开启事务) conn.setAutoCommit(false); //3.获得语句执行平台 String sql=" update account set money=3000 where aname=?"; PreparedStatement pst=conn.prepareStatement(sql); //执行 pst.setString(1, "xiaoliang"); // int y=1/0; pst.executeUpdate(); //提交事务 conn.commit(); pst.close(); conn.close(); } catch (ClassNotFoundException | SQLException e) { // TODO Auto-generated catch block //事务回滚 try { conn.rollback(); } catch (SQLException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } e.printStackTrace(); } } }
DBUtils事务操作
QueryRunner
有参构造:QueryRunner runner = new QueryRunner(DataSource dataSource);
有参构造将数据源(连接池)作为参数传入QueryRunner,QueryRunner会从连 接池中获得一个数据库连接资源操作数据库,所以直接使用无Connection参数 的update方法即可操作数据库
无参构造:QueryRunner runner = new QueryRunner();
无参的构造没有将数据源(连接池)作为参数传入QueryRunner,那么我们在使 用QueryRunner对象操作数据库时要使用有Connection参数的方法
package com.oracle.demo01; import java.sql.Connection; import java.sql.SQLException; import org.apache.commons.dbutils.QueryRunner; import com.oracle.tools.DBUtils; import com.oracle.tools.JDBCutils; public class DBUtilsDemo { public static void main(String[] args) { QueryRunner qr=new QueryRunner(); Connection conn=JDBCutils.getConn(); String sql=" update account set money=10 where aname=?"; try { //开启事务 conn.setAutoCommit(false); qr.update(conn,sql,"xiaoliang"); // int y=1/0; //提交事务 conn.commit(); } catch (SQLException e) { //事务回滚 try { conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); } } }
事物的特性和隔离级别
事务的特性ACID
1)原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作 要么都发生,要么都不发生。
2)一致性(Consistency)一个事务中,事务前后数据的完整性必须保持一致。
3)隔离性(Isolation)多个事务,事务的隔离性是指多个用户并发访问数据库时, 一个用户的 事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。
4)持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。
事务例子:转账
dao层
package com.oracle.dao; import java.sql.Connection; import java.sql.SQLException; import org.apache.commons.dbutils.QueryRunner; import com.oracle.tools.DBUtils; public class TransferDao { public void increaseMoney(String in,double money) throws SQLException{ QueryRunner qr=new QueryRunner(); Connection conn=DBUtils.getCurrentConnection(); String sql=" update account set money=money+? where aname=?"; qr.update(conn,sql,money,in); } public void unincreaseMoney(String out,double money) throws SQLException{ QueryRunner qr=new QueryRunner(); Connection conn=DBUtils.getCurrentConnection(); String sql=" update account set money=money-? where aname=?"; qr.update(conn,sql,money,out); } }
service层
package com.oracle.service; import java.sql.Connection; import java.sql.SQLException; import com.oracle.dao.TransferDao; import com.oracle.tools.DBUtils; public class TransferService { private TransferDao transferdao=new TransferDao(); public boolean transfer(String in,String out,double money){ boolean isTransferSuccess=true; try { //开启事务 DBUtils.start(); // int a=1/0; transferdao.increaseMoney(in, money); transferdao.unincreaseMoney(out, money); //提交事务 DBUtils.commit(); } catch (Exception e) { isTransferSuccess=false; //回滚事务 DBUtils.rollback(); e.printStackTrace(); } return isTransferSuccess; } }
tools层-DBUtils
package com.oracle.tools; import java.sql.Connection; import java.sql.SQLException; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSource; public class DBUtils { public static final String DRIVER = "com.mysql.jdbc.Driver"; public static final String URL = "jdbc:mysql://localhost:3306/bank?characterEncoding=utf8"; public static final String USERNAME = "root"; public static final String PASSWORD = "123456"; public static ThreadLocal<Connection> tl=new ThreadLocal<Connection>(); /* * 创建连接池BasicDataSource */ public static BasicDataSource dataSource = new BasicDataSource(); //静态代码块 static { //对连接池对象 进行基本的配置 dataSource.setDriverClassName(DRIVER); // 这是要连接的数据库的驱动 dataSource.setUrl(URL); //指定要连接的数据库地址 dataSource.setUsername(USERNAME); //指定要连接数据的用户名 dataSource.setPassword(PASSWORD); //指定要连接数据的密码 } /* * 返回连接池对象 */ public static DataSource getDataSource(){ return dataSource; } public static Connection getCurrentConnection(){ Connection conn=tl.get(); if(conn==null) { //第一种 conn=getConn(); tl.set(conn); //第二种, // tl.set(getConn()); // conn=tl.get(); } return conn; } //开启事务 public static void start(){ try { getCurrentConnection().setAutoCommit(false); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //提交事务 public static void commit(){ try { getCurrentConnection().commit(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //回滚事务 public static void rollback(){ try { getCurrentConnection().rollback(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //连接对象 public static Connection getConn(){ Connection conn=null; try { conn=dataSource.getConnection(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return conn; } }
web层
package com.oracle.web; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.oracle.service.TransferService; public class TransferServlet extends HttpServlet { private TransferService transferservice=new TransferService(); public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); String out=request.getParameter("out"); String in=request.getParameter("in"); double money=Double.parseDouble(request.getParameter("money")); //数值类型强转:byte>short>int>long>float>double //int a=(int)2.9; //向下转型:Object obj=new Person();Person p=(Person)obj; boolean flag=transferservice.transfer(in, out, money); response.setContentType("text/html;charset=utf-8"); if(flag){ response.getWriter().write("转账成功"); }else{ response.getWriter().write("转账失败"); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
转账jsp页面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <form action="${pageContext.request.contextPath }/TransferServlet" method="post"> 转出用户:<input type="text" name="out"><br> 转入用户<input type="text" name="in"><br> 金额:<input type="text" name="money"><br> <input type="submit" value="提交"><br> </form> </body> </html>