一、事务
学过数据库的人都知道,所谓事务是用户定义的一个数据库操作序列,这些操作要么全做,要么全都不做,它是一个不可分割的工作单位,而事务又有其ACID特性,分别是以下四种:
①原子性 指的事务中的操作要么全都做,要么全都不做
②一致性 指的是事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态
③隔离性 一个事务的执行不能被其他事务干扰
④持续性 一个事务一旦提交,它对数据库中的数据的改变都是永久性的
那么JDBC是如何对事务处理的呢?我们知道,在对数据库进行操作的时候,当在一个事务中执行多个操作的时候,要么事务执行完了然后所有的事务都被提交(commit),要么就是将整个事务roolback回滚到开始执行事务之前的最初状态,而JDBC当中是自动提交事务的,也就是说,如果执行了一条SQL语句,且执行成功,那么就会向数据库自动提交(commit),也就是说,默认情况下,如果JDBC中成功执行了一条SQL语句,那么我们是不能够回滚的
现在考虑这种情况,如果我想要在建立了一个数据库的连接的时候让多条SQL语句作为一个事务执行,即共用一个Connection连接,如果我执行到某一条SQL语句时出现了异常,导致这个事务未正常执行完,但是之前执行完的SQL语句已经由JDBC自动向数据库提交了,这就导致了严重的数据的不一致,所以,我们应该改变这种自动提交的方式。
为了改变上面的这种情况,让多个SQL语句作为一个事务执行,我们可以使用以下方法:
①在建立数据库连接后调用Connection对象的serAutoCommit(boolean i)并将里面的参数设置为false
②在所有SQL语句执行完后,调用commit()方法向数据库提交事务
③如果执行过程中出现了异常,则调用roolback()方法回滚事务
下面是具体的Demo:
import java.sql.Connection;
import java.sql.SQLException;
import org.junit.Test;
/*
* 用户TOM向Liily转账1000元
*/
public class TestTransaction {//事务的多个操作
@Test
public void transactionTest(){
Connection con = null;
try {
con = JDBCTools.getConnection();
con.setAutoCommit(false);
String sql = "UPDATE customer SET money=money-1000 WHERE id=?";
JDBCTools.update(con, sql,1);
sql = "UPDATE customer SET money=money+1000 WHERE id=?";
JDBCTools.update(con, sql,2);
con.commit();//数据更新完后提交事务
} catch (Exception e) {//如果遇到异常 就回滚事务
e.printStackTrace();
try {
con.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally{//事务执行完毕或者出现了异常后,释放数据库连接
JDBCTools.release(null, con, null);
}
}
}
//JDBCTools类
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JDBCTools {
public static void update(Connection con,String sql , Object ... args){
PreparedStatement ps = null;
try {
ps = con.prepareStatement(sql);
for(int i = 0;i<args.length;i++){//索引的下标从1开始 和数组不一样
ps.setObject(i+1, args[i]);
}
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws Exception{//连接数据库
String driverClass = null;
String url = null;
String user = null;
String password = null;
Properties properties = new Properties();
InputStream in = Review.class.getClassLoader().getResourceAsStream("jdbc.properties");
properties.load(in);
driverClass = properties.getProperty("driver");
url = properties.getProperty("jdbcurl");
user = properties.getProperty("user");
password = properties.getProperty("password");
Class.forName(driverClass);
return DriverManager.getConnection(url, user, password);
}
public static void release(Connection con , Statement state){//关闭数据库连接
if(state != null){
try {
state.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(con != null){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void release(ResultSet rs , Connection con , Statement state){//关闭数据库连接
if(rs != null)
{
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(state != null){
try {
state.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(con != null){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}