记账本开发记录——第十八天(2020.2.5)
今天学习了一个名为事务的东西。这个东西对于我是陌生的。事务,即主要用于处理一些操作量大,复杂度高的操作。在上学期的一系列学习中,由于系主任只是简单粗暴的想让我们学会增删改查,这种涉及工程的东西也难怪我们没有接触。但说到底还是要做工程的。今天对于事务进行了一个基本的了解。
首先,什么是事务,按照官方理解 就是一件事情有n个组成单元 要不这n个组成单元同时成功 要不n个单元就同时失败,就是将n个组成单元放到一个事务中。其实照自己的理解来说,就是将多个操作捆绑到一起,要成功就一起成功,要失败就一起失败。说到底是为了防止一些意外发生,比如一个转账操作,如果在执行完转出后发生了异常,转入操作无法执行了,那这个客户的钱不就没了?这上哪说理去。事物就是为了防止这种情况的发生。我们一般使用的数据库是mysql,mysql的事务如下:
默认的事务:一条sql语句就是一个事务 默认就开启事务并提交事务
手动事务:
1)显示的开启一个事务:start transaction
2)事务提交:commit代表从开启事务到事务提交 中间的所有的sql都认为有效 真正的更新数据库
3)事务的回滚:rollback 代表事务的回滚 从开启事务到事务回滚 中间的所有的 sql操作都认为无效数据库没有被更新
在了解了这个基础上,我们可以分别使用JDBC和DBUtils做个demo来测试。
1 package jdbc; 2 3 import java.sql.Connection; 4 import java.sql.DriverManager; 5 import java.sql.SQLException; 6 import java.sql.Statement; 7 8 import com.mysql.cj.jdbc.Driver; 9 10 public class JDBCDemo { 11 public static void main(String[] args) throws SQLException { 12 13 //通过jdbc去控制事物 14 Connection conn = DriverManager.getConnection("jdbc:mysql:////day19", "root", "abc456"); 15 //1.注册驱动 16 try { 17 Class.forName("com.mysql.jdbc.Driver"); 18 //2.获得connection 19 20 //手动开启事务 21 conn.setAutoCommit(false); 22 23 24 //3.获得执行平台 25 Statement stmt = conn.createStatement(); 26 27 //4.操作sql 28 stmt.executeUpdate("insert into account values(null,'jackson',3000)"); 29 30 //提交事务 31 conn.commit(); 32 33 stmt.close(); 34 conn.close(); 35 } catch (Exception e) { 36 e.printStackTrace(); 37 conn.rollback(); 38 } 39 40 } 41 42 }
1 package utils; 2 3 import java.sql.Connection; 4 import java.sql.SQLException; 5 6 import org.apache.commons.dbutils.QueryRunner; 7 8 public class DBUtilsDemo { 9 public static void main(String[] args) throws SQLException { 10 11 Connection conn = DataSourceUtils.getConnection(); 12 try { 13 QueryRunner runner = new QueryRunner(); 14 //开启事务 15 16 //runner.update("update account set money=10000 where name = 'tom'"); 17 //获得一个connection 18 19 runner.update(conn, "update account set money=10000 where name = 'tom'"); 20 conn.setAutoCommit(false); 21 //提交或回滚事务 22 conn.commit(); 23 } catch (SQLException e) { 24 conn.rollback(); 25 // TODO Auto-generated catch block 26 e.printStackTrace(); 27 } 28 29 } 30 31 }
通过这个demo更好的了解事务后,就可以做一个关于转账的基本操作了:
页面是这个样子的:
页面代码就不贴了。
web层:
package transfer.web; import java.io.IOException; import java.sql.SQLException; 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 transfer.service.TransferService; /** * Servlet implementation class TransferServlet */ @WebServlet("/Transfer") public class TransferServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public TransferServlet() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); //接收转账参数 String out = request.getParameter("out"); String in = request.getParameter("in"); String moneyStr = request.getParameter("money"); double money = Double.parseDouble(moneyStr); //调用业务层的转账方法 TransferService service = new TransferService(); boolean isTransferSuceess; try { isTransferSuceess = service.transfer(out,in,money); if(isTransferSuceess) { response.getWriter().write("转账成功"); }else { response.getWriter().write("转账失败"); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * @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层:
package transfer.service; import java.sql.Connection; import java.sql.SQLException; import transfer.dao.TransferDao; import utils.DataSourceUtils; public class TransferService { public boolean transfer(String out, String in, double money) throws SQLException { Connection conn = DataSourceUtils.getConnection(); //创建dao对象 TransferDao dao = new TransferDao(); boolean isTransferSuccess = true; try { //开启事务 conn.setAutoCommit(false); dao.out(conn,out,money); int i=1/0; dao.in(conn,in,money); } catch (Exception e) { isTransferSuccess = false; //回滚事务 conn.rollback(); e.printStackTrace(); }finally { conn.commit(); } return isTransferSuccess; } }
dao层:
package transfer.dao; import java.sql.Connection; import java.sql.SQLException; import org.apache.commons.dbutils.QueryRunner; import utils.DataSourceUtils; public class TransferDao { public void out(Connection conn,String out, double money) throws SQLException { QueryRunner runner = new QueryRunner(); //Connection conn = DataSourceUtils.getConnection(); String sql = "update account set money = money-? where name=?"; runner.update(conn,sql,money,out); } public void in(Connection conn,String in, double money) throws SQLException { QueryRunner runner = new QueryRunner(); //Connection conn = DataSourceUtils.getConnection(); String sql = "update account set money = money+? where name=?"; runner.update(conn,sql,money,in); } }
需要注意的是,我们对于事务的处理一般位于service层,在其中添加事务的基本操作。
(关于事务的内容还有很多,但碍于进度问题,这里暂时搁置)
明日:复习增删改查,后天使用DBUtils,数据库连接池,BeanUtils进行记账本的增删改查,将页面改写为jsp,将导航栏部分做成固定jsp等等。