面试题
事务是怎么处理的?
事务是通过设置连接里面的非自动AutoCommit属性来处理的。设置事务为非自动提交。,默认是自动提交的。
1:事务的概念
事务是一系列作为一个逻辑单元来执行的操作集合
它是数据库维护数据一致性的单位,它将数据库从一个一致状态,转变为新的另外一个一致状态
说的简单一点就是:如果一组处理步骤要么全部成功,要么全部失败,这样就保证了数据始终一直的状态
维护了数据的完整和可靠性
2 :jdbc处理事务的逻辑
详见jdbc事务.png
3:事务的属性
事务的4个属性:原子性、一致性、隔离性、持续性。这四个属性通常称为ACID特性。
原子性(atomicity):一个事务是一个不可分割的工作单位,事务中包括的所有操作要么都做,要么都不做。
一致性(consistency):事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
隔离性(isolation):一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,
并发执行的各个事务之间不能互相干扰。
持久性(durability):持续性也称永久性(permanence),指一个事务一旦提交,
它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。
4:事务的传播特性
事务的传播特性指处于不同事物的方法在相互调用时,执行期间,事务的维护情况
一般有两种方式:
* PROPAGATION_REQUIED :如果存在一个事务,则支持当前事务,如果没有事务则开启。
* PROPAGATION_REQUIED_NEW :总是开启一个新事务。
5:事务管理的类型
事务管理分为两种类型,分为编程式事务和声明式事务
编程式事务
编程式事务管理可以清楚的定义事务的边界
可以实现细粒度的事务控制,开发者可以通过程序代码来控制你的事务何时开始,何时结束,类似于jdbc事务.png
但是事务的控制与业务代码耦合在一起,不能共用 ,而且开发效率低,不便于维护
声明式事务
声明式事务可以结合spring AOP的概念,只需要通过配置在指定的方法中加入事务控制.
如果需要修改或者删除事务,移除配置即可,解除了系统服务(事务)与业务代码的耦合,而且方便管理
在实际开发中,一般提倡用声明式事务管理
6:spring跟事务的关系
* 事务原本是数据库中的概念,是在dao层
但是一般情况下,我们会把事务管理提升到我们的业务层(service)
这是为了更好的是用事务来管理我们的业务逻辑
* spring并不直接管理事务,而是提供了多种事务管理器
根据不同的数据应用方式,(jdbc(自定义封装的jdbc,jdbctemplate,mybatis)/hibernate)提供了对应的事务管理器
jdbc:DataSourceTransactionManager
hibenate:HibernateTranactionManager
所有的事务管理器实现了一个共同的接口
org.springframework.transaction.PlatformTransactionManager
他提供了三个方法 commit rollback getTransaction(TransactionDefinition(用来定义事务的一系列属性))
7:Spring实现事务有三种方式
* 基于xml配置
* 注解
* aspectJ
8:模拟转账
9: spring基于xml配置实现事务
* 环境搭建:引入jar,引入aop约束
aopalliance-1.0.jar
spring-aop-4.2.1.RELEASE.jar
spring-tx.jar
* xml配置事务
详见applicationContext.xml AccountWithTransTest.java
10: spring注解方式实现事务
在第九步的基础上引入tx约束
详见 applicationContext-annotation.xml
AccountWithTransAnnoTest.Java
11: spring AspectJ实现事务
AccountDao
package com.tz.spring.sysmanage.dao.impl;
import org.springframework.jdbc.core.JdbcTemplate;
import com.tz.spring.sysmanage.dao.IAccountDao;
/**
*
* @author Administrator
*
*/
public class AccountDao implements IAccountDao{
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public boolean addAccountMoney(String account, double money) {
boolean updateFlag = false;
String updateSql = "UPDATE M_ACCOUNT SET AC_MONEY = AC_MONEY+? WHERE AC_NAME = ? ";
int rows = this.jdbcTemplate.update(updateSql, money,account);
if(rows>0){
updateFlag = true;
}
return updateFlag;
}
public boolean subAccountMoney(String account, double money) {
boolean updateFlag = false;
String updateSql = "UPDATE M_ACCOUNT SET AC_MONEY = AC_MONEY-? WHERE AC_NAME = ? ";
int rows = this.jdbcTemplate.update(updateSql, money,account);
if(rows>0){
updateFlag = true;
}
return updateFlag;
}
}
AccountService
package com.tz.spring.sysmanage.service.impl;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.tz.spring.sysmanage.dao.IAccountDao;
import com.tz.spring.sysmanage.service.IAccountService;
/**
*
* @author Administrator
*
*/
public class AccountService implements IAccountService{
private IAccountDao accountDao;
public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
}
@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED )
public boolean operateAccount(String fromAccount, String toAccount ,double money) {
System.out.println("---------------转账开始---------------");
accountDao.subAccountMoney(fromAccount, money);
System.out.println("转账金额---------------"+money);
int i= 1/0;
accountDao.addAccountMoney(toAccount, money);
System.out.println("---------------转账结束---------------");
return true;
}
}
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id = "accountService"
class = "com.tz.spring.sysmanage.service.impl.AccountService">
<property name="accountDao" ref = "accountDao"></property>
</bean>
<bean id = "accountDao"
class = "com.tz.spring.sysmanage.dao.impl.AccountDao">
<property name="jdbcTemplate" ref = "jdbcTemplate"></property>
</bean>
<bean id= "jdbcTemplate" class = "org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref = "dataSource"></property>
</bean>
<context:property-placeholder location = "classpath:jdbc.properties"/>
<bean id= "dataSource"
class= "com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<bean id = "txMgr" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<property name="dataSource" ref = "dataSource"></property>
</bean>
<bean id= "transProxy" class= "org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref= "txMgr"></property>
<property name="target" ref = "accountService"></property>
<property name="transactionAttributes">
<props>
<prop key="oper*">ISOLATION_DEFAULT,PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
</beans>
applicationContext-annotation.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id = "accountService"
class = "com.tz.spring.sysmanage.service.impl.AccountService">
<property name="accountDao" ref = "accountDao"></property>
</bean>
<bean id = "accountDao"
class = "com.tz.spring.sysmanage.dao.impl.AccountDao">
<property name="jdbcTemplate" ref = "jdbcTemplate"></property>
</bean>
<bean id= "jdbcTemplate" class = "org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref = "dataSource"></property>
</bean>
<context:property-placeholder location = "classpath:jdbc.properties"/>
<bean id= "dataSource"
class= "com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<bean id = "txMgr" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<property name="dataSource" ref = "dataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="txMgr"/>
</beans>
AccountWithTransAnnoTest
package com.tz.spring.sysmanage.test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.tz.spring.sysmanage.service.IAccountService;
public class AccountWithTransAnnoTest {
private ApplicationContext ac = null;
@Before
public void init(){
ac = new ClassPathXmlApplicationContext("applicationContext-annotation.xml");
}
@Test
public void testOperatorAccount(){
IAccountService accountService = (IAccountService)ac.getBean("accountService");
accountService.operateAccount("李四", "张三", 100);
}
}
applicationContext-aspectJ.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id = "accountService"
class = "com.tz.spring.sysmanage.service.impl.AccountService">
<property name="accountDao" ref = "accountDao"></property>
</bean>
<bean id = "accountDao"
class = "com.tz.spring.sysmanage.dao.impl.AccountDao">
<property name="jdbcTemplate" ref = "jdbcTemplate"></property>
</bean>
<bean id= "jdbcTemplate" class = "org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref = "dataSource"></property>
</bean>
<context:property-placeholder location = "classpath:jdbc.properties"/>
<bean id= "dataSource"
class= "com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<bean id = "txMgr" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<property name="dataSource" ref = "dataSource"></property>
</bean>
<tx:advice id = "txAdvice" transaction-manager="txMgr">
<tx:attributes>
<tx:method name="oper*" isolation="DEFAULT" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut expression="execution(* *..AccountService.*(..))" id="accountPointCut"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="accountPointCut"/>
</aop:config>
</beans>