1.事务
数据库**事务( transaction)**是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。
比如,我们去银行转账,操作可以分为下面两个环节:
(1)从第一个账户划出款项。 String sql1;
(2)将款项存入第二个账户。 String sql2;
在这个过程中,两个环节是关联的。**第一个账户划出款项必须保证正确的存入第二个账户,如果第二个环节没有完成,整个的过程都应该取消,否则就会发生丢失款项的问题。**整个交易过程,可以看作是一个事物,成功则全部成功,失败则需要全部撤消,这样可以避免当操作的中间环节出现问题时,产生数据不一致的问题。
2.具体Java应用
在一个项目中,要求下列三条语句组成一个事务
String sql = "insert into Train_ticket (user_id,train_id,start_station_name,end_station_name,carriage,seat_grade,seat_location,ride_time,start_time,end_time,price) " +
"values ('"+ticket.getUser_id()+"','"+ticket.getTrain_id()+"','"+ticket.getStart_station_name()+"','"+ticket.getEnd_station_name()+"',"+ticket.getCarriage()+","+ticket.getSeat_grade()+"," +
"'"+ticket.getSeat_location()+"','"+ticket.getRide_time()+"','"+ticket.getStart_time()+"','"+ticket.getEnd_time()+"',"+ticket.getPrice()+");";
String sql2 = "update Train_seat set occupy=0 where train_id='"+ticket.getTrain_id()+"' and carriage="+ticket.getCarriage()+" and seat_location='"+ticket.getSeat_location()+"'";
String sql3 = "insert into Ride_train values ('"+ticket.getUser_id()+"','"+ticket.getTrain_id()+"',' "+ticket.getRide_time()+" "+ticket.getStart_time()+"')";
如何确保其原子性:
利用事务的提交和回滚
将组成事务的SQL语句封装到一个方法中要不均成功提交,要不均失败
/***
* 数据库的事务并发控制
*/
public class Affairs {
static Connection conn=null;
static {
conn=DBConnection.getConnection();
}
public static int transaction_control(String sql[]){
Statement stmt = null;
int result = 0;
try {
// 开启事务
//不把其设置为true之前都是一个当作一个事务来处理
conn.setAutoCommit(false);
// 创造SQL语句
// 执行SQL语句
stmt = conn.createStatement();
for (int i = 0; i < sql.length; i++) {
stmt.executeUpdate(sql[i]);
}
// 提交事务
conn.commit();
System.out.println( "OK!" );
}
//发生任何错误均需回滚
catch (SQLIntegrityConstraintViolationException e3) {
result = -1;//主码冲突,返回支付失败
try {
// 回滚事务
//撤销上面对事务的所有操作哈!
conn.rollback();
} catch (SQLException e2){
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("有错误!");
try {
// 回滚事务
//撤销上面对事务的所有操作哈!
conn.rollback();
} catch (SQLException e2){
}
}
return result;
}
}
工具类DBConnection
//com.mysql.cj.jdbc.Driver数据库驱动
private static final String DBDRIVER="com.mysql.cj.jdbc.Driver";
//IP地址202.194.14.120 端口号3306 数据库的名字TrainTicketSystem
private static final String DBURL="jdbc:mysql://localhost:3306/TrainTicketSystem?&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true";
//用户名root
private static final String DBUSER="root";
//密码***
private static final String DBPASSWORD="***";
static {
try {
Class.forName(DBDRIVER);
System.out.println("加载驱动成功");
} catch (ClassNotFoundException e) {
e.printStackTrace();
System.out.println("加载驱动失败");
}
}
public static Connection getConnection() {
Connection conn=null;
try {
conn=DriverManager.getConnection(DBURL,DBUSER,DBPASSWORD);
System.out.println("连接成功");
} catch (SQLException e) {
// TODO: handle exception
e.printStackTrace();
System.out.println("发生连接异常");
}
return conn;
}
3.关键
在执行之前一定要有 conn.setAutoCommit( false );这句话就是设置不自动提交,如果自动提交就是相当于一个sql语句就是一个事务.
如果 conn.setAutoCommit( true )那么就是设置自动提交,第一句能够完成提交,数据库也会有相应的记录,但是第二句如果报错就无法回滚。
总结:事务回滚之前要 conn.setAutoCommit( false );这样吧下面的语句相当于一个事务,一旦出现错误就会撤销所有操作.