在JAVA中什么是事务?
通常的观念认为,事务仅与数据库相关。事务必须服从ISO/IEC所制定的ACID原则。ACID是原子性(atomicity)、一致性(consistency)、隔离性isolation)和持久性(durability)的缩写。事务的原子性表示事务执行过程中的任何失败都将导致事务所做的任何修改失效。一致性表示当事务执行失败时,所有被该事务影响的数据都应该恢复到事务执行前的状态。隔离性表示在事务执行过程中对数据的修改,在事务提交之前对其他事务不可见。持久性表示已提交的数据在事务执行失败时,数据的状态都应该正确。
通俗的理解,事务是一组原子操作单元,从数据库的角度来说,就是一组SQL命令,要么全部执行成功。若因为其中一条指令执行有错误,则撤销先前执行过的所有指令。更简单的来说,要么全部执行成功,要么全部执行不成功。
在Java中,操作数据库通过JDBC来实现,增、删、改都是通过相应的方法间接实现的,事务的控制也相应转移到java程序中,因此数据库操作的事务习惯上就称为java事务。
为什么要使用事务?
直白一点来说,就是为了给自己留条后路。因为对于数据库的操作,是持久性的,所以我们需要谨慎对待,如果没有满足条件,对数据库的操作就会失效,也就是给自己一次反悔的机会,泼出去的水还可以收回来
什么时候使用事务?
事务是为了解决数据安全操作提出的,事务控制实际上就是控制数据的安全访问。举一个简单的例子:比如银行的转账业务,账户A要将自己账户上的666转到账户B下面,A账户余额首先需要减去666元,然后B账户要增加666元,假如中间网络出现了问题,A账户减去666元已经结束,B因为网络中断而操作失败,那么整个业务失败,必须要做出控制保证业务的正确性,这个时候就需要事务,要么全部执行成功,要么操作全部撤销,这样就保证了数据的安全性。
Java事务的类型
java事务的类型有三种:JDBC事务、JTA(java Transaction API)事务、容器事务。
1、JDBC事务控制的局限性在一个数据库连接内,但是其使用简单。
2、JTA事务的功能强大,事务可以跨越多个数据库或多个DAO,使用也比较复杂。
3、容器事务,主要指的是J2EE应用服务器提供的事务管理,局限于EJB应用使用。
//JDBC事务
public static void main(String[] args) throws SQLException, ClassNotFoundException {
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/user";
String user = "root";
String password = "123456";
Connection con = (Connection) DriverManager.getConnection(url, user, password);
try {
//取消自动提交
//如果设成false,那就是JDBC不自动提交,需要手动的使用commit或者rollback来进行提交或者回滚数据.
con.setAutoCommit(false);
Statement stmt = (Statement) con.createStatement();
//进行数据插入
String sql = "insert into users(email,password) values('" + "jack@163.com" + "','" + "jack" + "');";
boolean flag = stmt.execute(sql);
System.out.println(flag);
//人为制造一个错误,结果就是数据库并没有插入这条数据,也就是数据发生了回滚
//异常被捕获之后,就不在执行下面的语句,而是执行catch中的语句
//如果没有异常,数据就会被提交到数据库
System.out.println(1/0);
//手动提交
con.commit();
} catch (Exception e) {
//如果发生错误,就回滚
con.rollback();
} finally {
con.close();
}
}
spring boot事务管理:
在启动主类添加注解:@EnableTransactionManagement 来启用注解式事务管理,相当于之前在xml中配置的<tx:annotation-driven />注解驱动。
在需要事务的类或者方法上面添加@Transactional(rollbackFor = Exception.class)注解,里面可以配置需要的粒度:
在逻辑上如果需要手动回滚则加入下代码
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();