进行事务操作主要是使用Connection中的方法:
开启事务:public void setAutoCommit(boolean autoCommit) throws SQLException true:自动提交,也就是没执行一条SQL语句都是单独的事务 false:手动提交,就相当于开启事务并在提交前都处于事务的状态中 提交事务:public void commit() throws SQLException 回滚事务:public void rollback() throws SQLException
try { conn.setAutoCommit(false); // 开启事务 // 执行SQL语句 // 执行SQL语句 // 执行SQL语句 // 执行SQL语句 conn.commit(); // 提交事务 }catch() { conn.rollback(); // 回滚事务 }
这样操作的话,在执行SQL语句的时候如果出现了异常,那么就马上会跳转到rollback()回滚方法,从而保证异常不会影响数据库中的数据。
同一事务中所有的操作都是一个Connection对象进行的
首先在MySQL中创建一个account表并插入几个值:
然后是Dao层的数据库连接操作代码:
package logic; import java.sql.Connection; import java.sql.SQLException; import org.junit.jupiter.api.Test; import JDBC.JdbcUtils; import dao.UpdataDao; public class TransferDemo { public void transfer(String from, String to, double money) { // 获取SQL对象 Connection conn = null; try { conn = JdbcUtils.getConnection(); // 开启事务 conn.setAutoCommit(false); // 转账 UpdataDao upd = new UpdataDao(); upd.upDate(conn, from, -money); // 减去money upd.upDate(conn, to, money); // 加上money //提交事务 conn.commit(); // 关闭资源 conn.close(); }catch(Exception e) { try { // 回滚事务 conn.rollback(); conn.close(); // 关闭资源 } catch (SQLException e1) { throw new RuntimeException(e1); } } } }
package dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Statement; public class UpdataDao { /** * 操作数据库中的数据 * @param conn SQL对象 * @param name 要操作对象的名字 * @param money 加减的金额 */ public void upDate(Connection conn, String name, double money) { try { // SQL模板 String sql = "UPDATE account SET balance=balance+? WHERE name=?"; // 这个是更新数据的模板 String sqlStmt = "SELECT name FROM account"; // 这个检索名称的模板 // 绑定模板 PreparedStatement pstmt = conn.prepareStatement(sql); Statement stmt = conn.createStatement(); // 获取数据表 ResultSet rs = stmt.executeQuery(sqlStmt); while(rs.next()) {// 移动光标 if(rs.getString("name").equals(name)) { // 判断当前光标获取的名字是否正确 System.out.println("找到你啦!!"); pstmt.setDouble(1, money); pstmt.setString(2, name); // 执行 pstmt.executeUpdate(); break; } } // 没有这个名称则抛出异常 if(rs.isAfterLast()) { // 光标已经在最后了 System.out.println("没有找到!!"); throw new RuntimeException("名称不存在!!!"); } stmt.close(); // stmt只在本方法中被使用,所以可以在使用后关闭 }catch (Exception e) { throw new RuntimeException(e); } } }
然后是JSP前端页面代码:
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>title</title> </head> <body> <div align="center"> <form action="<c:url value='/AServlet'/>" method="post"> 转账人:<input type="text" name="from"/><br/><br/> 收款人:<input type="text" name="to"/><br/><br/> 转账金额:<input type="text" name="money" size="18px"/><br/><br/> <input type="submit" value="提交"/><br/> </form> </div> </body> </html>
最后是Servlet处理请求:
package servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import logic.TransferDemo; @WebServlet("/AServlet") public class AServlet extends HttpServlet { private static final long serialVersionUID = 9081505028320745516L; private logic.TransferDemo tf = new TransferDemo(); protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); // 获取参数 String from = request.getParameter("from"); String to = request.getParameter("to"); double money = Double.parseDouble(request.getParameter("money")); this.tf.transfer(from, to, money); // 调用方法来设置参数 response.getWriter().print("从 " + from + " 转账 " + money +" 到 " + to + " 的账户上"); } }
启动服务器,输入参数:
这里我分别输入了不存在的转账人、不存在的收款人和转账人、收款人 同时不存在的三种参数,查看结果:
数据库中的数据没有变化,说明进行了事务的回滚操作,那么再进行正确参数的输入:
再次查看:
这次执行后数据库进行了一加一减的数据变化,说明转账操作成功。