数据库是具有事务性的,这是数据库与其他存储方式的区别之一。
那么什么是事务性呢?简单来说一个事务内会执行多个操作,这些操作要么全部执行成功,要么全部执行失败。就比如说转账:A向B转账200元是一个事务,但他包含两个操作,一个是A减少200元,另一个是B增加200元,这两个操作必须都操作成功才能说这个事务执行成功,否则事务执行失败。
事务会有两个结果,提交(Commit)与回滚(Rollback),如果事务内的操作全部完成则提交,将结果保存进数据库,否则回滚,数据库内数据不会有任何改动。
下面看一个例子
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.sql.*"%>
<%@ page import="java.util.Date"%>
<%@ page import="java.sql.Timestamp"%>
<div style="padding: 2px; text-align: left;">
<a href="${pageContext.request.requestURI}">只显示余额</a> <br>
<a href="${pageContext.request.requestURI}?action=a2b">A向B转账200元</a><br>
<a href="${pageContext.request.requestURI}?action=b2a">B向A转账200元</a>
</div>
<%
Connection conn=null;
Statement stmt=null;
ResultSet rs=null;
try{
DriverManager.registerDriver(new com.mysql.jdbc.Driver());//注册驱动
conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/account","root","root");//获取数据库连接
stmt=conn.createStatement();
rs=stmt.executeQuery("select * from tb_currency");//查询结果集
%>
<table bgcolor="#CCCCCC" cellspacing=1 cellpadding=5 width=100%>
<caption ><FONT SIZE=4><B>转账记录表</B></FONT></caption>
<tr bgcolor=#DDDDDD>
<th>账号</th>
<th>余额</th>
<th>最后修改日期</th>
</tr>
<%
while(rs.next())
{
String account=rs.getString("account");//获取账户名
double currency=rs.getDouble("currency");//获取账户余额
String last_modifield=rs.getTimestamp("last_modified").toString();//获取上次操作时间
out.println("<tr bgcolor=#FFFFFF>");
out.println("<td align=center>"+account+"</td>");//将账户名显示在表中
out.println("<td align=center>"+currency+"</td>");//将余额显示在表中
out.println("<td align=center>"+last_modifield+"</td>"); //将上次操作时间显示在表中
out.println("</tr>");
}
}catch(SQLException e)
{
out.println("发生异常:"+e.getMessage());
e.printStackTrace();
}finally{
if(rs!=null) rs.close();
if(stmt!=null) stmt.close();
if(conn!=null) conn.close();
}
%>
</table>
<%
String action=request.getParameter("action");//获取action操作
if("a2b".equals(action))
{
out.println("业务:A向B转账200元。<br/>");
try
{
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/account","root","root");
conn.setAutoCommit(false);//将自动提交设为false
stmt=conn.createStatement();
String sql1="UPDATE tb_currency SET currency=currency-200 WHERE account='A'and currency>=200 ";
int result1=stmt.executeUpdate(sql1);
out.println("A账号扣款200元,结果:"+ (result1==1?"成功":"失败")+"<br/>");
String sql2="UPDATE tb_currency SET currency=currency+200 WHERE account='B'";
int result2=stmt.executeUpdate(sql2);
out.println("B账号进款200元,结果:"+ (result2==1?"成功":"失败")+"<br/>");
if(result1==1 && result2==1)
{
conn.commit();//提交事务
out.println("转账成功,事务提交。<a href='listCurrency.jsp'>点此刷新账表</a>");
}else{
conn.rollback();//事务回滚
out.println("转账失败,事务回滚。");
}
}finally{
if(stmt!=null) stmt.close();
if(conn!=null) conn.close();
}
}else if("b2a".equals(action))
{
out.println("业务:B向A转账200元。<br/>");
try
{
DriverManager.registerDriver(new com.mysql.jdbc.Driver());//注册驱动
conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/account","root","root");//获取连接
conn.setAutoCommit(false);//将自动提交设为false
stmt=conn.createStatement();
String sql1="UPDATE tb_currency SET currency=currency-200 WHERE account='B'and currency>=200 ";
int result1=stmt.executeUpdate(sql1);
out.println("B账号扣款200元,结果:"+ (result1==1?"成功":"失败")+"<br/>");
String sql2="UPDATE tb_currency SET currency=currency+200 WHERE account='A'";
int result2=stmt.executeUpdate(sql2);
out.println("A账号进款200元,结果:"+ (result2==1?"成功":"失败")+"<br/>");
if(result1==1 && result2==1)
{
conn.commit();//提交事务
out.println("转账成功,事务提交。 <a href='listCurrency.jsp'>点此刷新账表</a>");
}else{
conn.rollback();//事务回滚
out.println("转账失败,事务回滚。");
}
}finally{
if(stmt!=null) stmt.close();
if(conn!=null) conn.close();
}
}
%>
A向B转200,操作成功,事务提交
B向A转200,由于B余额不足,操作失败,事务回滚。