
事务是指数据库中一组操作,这些操作要么全部被执行,要么全部不被执行。在事务中,如果任何一个操作失败,则整个事务都会被回滚,即所有操作都不会生效。这样可以保证数据库的一致性和完整性。
事务是指一组操作被看作是一个单独的工作单元,这组操作要么全部完成,要么全部不完成,不会出现部分完成的情况。事务的作用主要包括以下几个方面:
以上是事务的主要作用,通过使用事务可以保证数据的完整性和一致性,提高数据库的并发能力和可靠性。
解决方案: (表级读锁)



Spring事务是指基于Spring框架实现的一种事务管理机制,它可以保证数据操作的一致性和完整性。通过使用Spring的事务管理,我们可以很方便地实现声明式事务,避免手动管理事务的繁琐和容易出错。同时,Spring事务还支持多种事务隔离级别和传播行为,可以根据需求进行灵活配置。
Spring为业务层提供了整套的事务解决方案
此接口定义了事务的基本操作
获取事务 :
TransactionStatus getTransaction(TransactionDefinition definition)提交事务 :
void commit(TransactionStatus status) 回滚事务 :
void rollback(TransactionStatus status)此接口定义了事务的基本信息
获取事务定义名称
String getName()获取事务的读写属性
boolean isReadOnly()获取事务隔离级别
int getIsolationLevel()获事务超时时间
int getTimeout()获取事务传播行为特征
int getPropagationBehavior()此接口定义了事务在执行过程中某个时间点上的状态信息及对应的状态操作

银行转账业务说明
银行转账操作中,涉及从A账户到B账户的资金转移操作。数据层仅提供单条数据的基础操作,未设计多账户间的业务操作。
/**
* 转账操作
* @param outName 出账用户名
* @param inName 入账用户名
* @param money 转账金额
*/
public void transfer(String outName,String inName,Double money);public void transfer(String outName,String inName,Double money){
accountDao.inMoney(outName,money); accountDao.outMoney(inName,money);
}<update id="inMoney">
update account set money = money + #{money} where name = #{name}
</update>
<update id="outMoney">
update account set money = money - #{money} where name = #{name}
</update>public void transfer(String outName,String inName,Double money){
//创建事务管理器
DataSourceTransactionManager dstm = new DataSourceTransactionManager();
//为事务管理器设置与数据层相同的数据源
dstm.setDataSource(dataSource);
//创建事务定义对象
TransactionDefinition td = new DefaultTransactionDefinition();
//创建事务状态对象,用于控制事务执行
TransactionStatus ts = dstm.getTransaction(td);
accountDao.inMoney(outName,money);
int i = 1/0; //模拟业务层事务过程中出现错误
accountDao.outMoney(inName,money);
//提交事务
dstm.commit(ts);
}将业务层的事务处理功能抽取出来制作成AOP通知,利用环绕通知运行期动态织入
public Object tx(ProceedingJoinPoint pjp) throws Throwable {
DataSourceTransactionManager dstm = new DataSourceTransactionManager();
dstm.setDataSource(dataSource);
TransactionDefinition td = new DefaultTransactionDefinition();
TransactionStatus ts = dstm.getTransaction(td);
Object ret = pjp.proceed(pjp.getArgs());
dstm.commit(ts);
return ret;
}配置AOP通知类,并注入dataSource
<bean id="txAdvice" class="com.itheima.aop.TxAdvice">
<property name="dataSource" ref="dataSource"/>
</bean>使用环绕通知将通知类织入到原始业务对象执行过程中
<aop:config>
<aop:pointcut id="pt" expression="execution(* *..transfer(..))"/>
<aop:aspect ref="txAdvice">
<aop:around method="tx" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>声明式事务是建立在AOP之上的,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>使用tx命名空间配置事务专属通知类
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="*" read-only="false" />
<tx:method name="get*" read-only="true" />
<tx:method name="find*" read-only="true" />
</tx:attributes>
</tx:advice>使用aop:advisor在AOP配置中引用事务专属通知类
<aop:config>
<aop:pointcut id="pt" expression="execution(* *..*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
</aop:config>名称:tx:advice
类型:标签
归属:beans标签
作用:专用于声明事务通知
格式:
<beans>
<tx:advice id="txAdvice" transaction-manager="txManager">
</tx:advice>
</beans>基本属性:
名称:tx:attributes
类型:标签
归属:tx:advice标签
作用:定义通知属性
格式:
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
</tx:attributes>
</tx:advice>基本属性:
名称:tx:method
类型:标签
归属:tx:attribute标签
作用:设置具体的事务属性
格式:
<tx:attributes>
<tx:method name="*" read-only="false" />
<tx:method name="get*" read-only="true" />
</tx:attributes>说明:
通常事务属性会配置多个,包含1个读写的全事务属性,1个只读的查询类事务属性
tx:method属性



名称:@Transactional
类型:方法注解,类注解,接口注解
位置:方法定义上方,类定义上方,接口定义上方
作用:设置当前类/接口中所有方法或具体方法开启事务,并指定相关事务属性
范例:
@Transactional(
readOnly = false,
timeout = -1,
isolation = Isolation.DEFAULT,
rollbackFor = {ArithmeticException.class, IOException.class},
noRollbackFor = {},
propagation = Propagation.REQUIRES_NEW
)名称:tx:annotation-driven
类型:标签
归属:beans标签
作用:开启事务注解驱动,并指定对应的事务管理器
范例:
<tx:annotation-driven transaction-manager="txManager"/>名称:@EnableTransactionManagement
类型:类注解
位置:Spring注解配置类上方
作用:开启注解驱动,等同XML格式中的注解驱动
范例:
@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")
@Import({JDBCConfig.class,MyBatisConfig.class,TransactionManagerConfig.class})
@EnableTransactionManagement
public class SpringConfig {
}public class TransactionManagerConfig {
@Bean
public PlatformTransactionManager getTransactionManager(@Autowired DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
}public class JDBCConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String userName;
@Value("${jdbc.password}")
private String password;
@Bean("dataSource")
public DataSource getDataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
//注册JdbcTemplate模块对象bean
@Bean("jdbcTemplate")
public JdbcTemplate getJdbcTemplate(@Autowired DataSource dataSource){
return new JdbcTemplate(dataSource);
}
@Bean("jdbcTemplate2")
public NamedParameterJdbcTemplate getJdbcTemplate2(@Autowired DataSource dataSource){
return new NamedParameterJdbcTemplate(dataSource);
}
}提供标准的sql语句操作API
public void save(Account account) {
String sql = "insert into account(name,money)values(?,?)";
jdbcTemplate.update(sql,account.getName(),account.getMoney());
}提供标准的具名sql语句操作API
public void save(Account account) {
String sql = "insert into account(name,money)values(:name,:money)";
Map pm = new HashMap();
pm.put("name",account.getName());
pm.put("money",account.getMoney());
jdbcTemplate.update(sql,pm);
}@PropertySource("redis.properties")
public class RedisConfig {
@Value("${redis.host}")
private String hostName;
@Value("${redis.port}")
private Integer port;
// @Value("${redis.password}")
// private String password;
@Value("${redis.maxActive}")
private Integer maxActive;
@Value("${redis.minIdle}")
private Integer minIdle;
@Value("${redis.maxIdle}")
private Integer maxIdle;
@Value("${redis.maxWait}")
private Integer maxWait;
@Bean
//配置RedisTemplate
public RedisTemplate createRedisTemplate(RedisConnectionFactory redisConnectionFactory){
//1.创建对象
RedisTemplate redisTemplate = new RedisTemplate();
//2.设置连接工厂
redisTemplate.setConnectionFactory(redisConnectionFactory);
//3.设置redis生成的key的序列化器,对key编码进行处理
RedisSerializer stringSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
//4.返回
return redisTemplate;
}
@Bean
//配置Redis连接工厂
public RedisConnectionFactory createRedisConnectionFactory(RedisStandaloneConfiguration redisStandaloneConfiguration,GenericObjectPoolConfig genericObjectPoolConfig){
//1.创建配置构建器,它是基于池的思想管理Jedis连接的
JedisClientConfiguration.JedisPoolingClientConfigurationBuilder builder = (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)JedisClientConfiguration.builder();
//2.设置池的配置信息对象
builder.poolConfig(genericObjectPoolConfig);
//3.创建Jedis连接工厂
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration,builder.build());
//4.返回
return jedisConnectionFactory;
}
@Bean
//配置spring提供的Redis连接池信息
public GenericObjectPoolConfig createGenericObjectPoolConfig(){
//1.创建Jedis连接池的配置对象
GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
//2.设置连接池信息
genericObjectPoolConfig.setMaxTotal(maxActive);
genericObjectPoolConfig.setMinIdle(minIdle);
genericObjectPoolConfig.setMaxIdle(maxIdle);
genericObjectPoolConfig.setMaxWaitMillis(maxWait);
//3.返回
return genericObjectPoolConfig;
}
@Bean
//配置Redis标准连接配置对象
public RedisStandaloneConfiguration createRedisStandaloneConfiguration(){
//1.创建Redis服务器配置信息对象
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
//2.设置Redis服务器地址,端口和密码(如果有密码的话)
redisStandaloneConfiguration.setHostName(hostName);
redisStandaloneConfiguration.setPort(port);
// redisStandaloneConfiguration.setPassword(RedisPassword.of(password));
//3.返回
return redisStandaloneConfiguration;
}
}RedisTemplate对象结构

public void changeMoney(Integer id, Double money) {
redisTemplate.opsForValue().set("account:id:"+id,money);
}
public Double findMondyById(Integer id) {
Object money = redisTemplate.opsForValue().get("account:id:" + id);
return new Double(money.toString());
}策略模式(Strategy Pattern)使用不同策略的对象实现不同的行为方式,策略对象的变化导致行为的变化。
