Spring jpa缓存和事务

最后发布时间:2021-08-28 21:55:53 浏览量:

一级缓存

JPA默认情况下和MyBatis一样开启一级缓存。JPA是针对与entityManager,Mybatis是针对于namespace。
同一个session可以使用缓存

 @Autowired
    EntityManager entityManager;
@Test
public void testSecondLevelCache(){
    Customer customer1 = entityManager.find(Customer.class, 1);
    Customer customer2 = entityManager.find(Customer.class, 1);
}

图片alt

图片alt

二级缓存

JPA的二级缓存是跨entityManager的,JPA的二级缓存需要显式配置。
事务提交后仍可以使用缓存

@Cacheable(true)//这里表示启用二级缓存
@Table(name="JPA_CUTOMERS")
@Entity
public class Customer {
    //...
}
@Test
    public void testSecondLevelCache(){
        Customer customer1 = entityManager.find(Customer.class, 1);
 
        transaction.commit();
        entityManager.close();
 
        entityManager = entityManagerFactory.createEntityManager();
        transaction = entityManager.getTransaction();
        transaction.begin();
 
        Customer customer2 = entityManager.find(Customer.class, 1);
    }

图片alt

图片alt

事务

@EnableTransactionManagement
public class BioinfoApplication {
	public static void main(String[] args) {
		SpringApplication.run(BioinfoApplication.class, args);
	}
}
@Service
public class RoleServiceImpl {
@Autowired
RoleRepository roleRepository;
	void test{
		roleRepository.findById(1);
		roleRepository.findById(1);
		Role role = entityManager.find(Role.class, 1);
		Role role2 = entityManager.find(Role.class, 1);
	}
}

事务不在service层处理

Hibernate: select role0_.id as id1_11_0_, role0_.en_name as en_name2_11_0_, role0_.name as name3_11_0_ from t_role role0_ where role0_.id=?
Hibernate: select role0_.id as id1_11_0_, role0_.en_name as en_name2_11_0_, role0_.name as name3_11_0_ from t_role role0_ where role0_.id=?
Hibernate: select role0_.id as id1_11_0_, role0_.en_name as en_name2_11_0_, role0_.name as name3_11_0_ from t_role role0_ where role0_.id=?
Hibernate: select role0_.id as id1_11_0_, role0_.en_name as en_name2_11_0_, role0_.name as name3_11_0_ from t_role role0_ where role0_.id=?
@Service
@Transactional
public class RoleServiceImpl {
@Autowired
RoleRepository roleRepository;
	void test{
		roleRepository.findById(1);
		roleRepository.findById(1);
		Role role = entityManager.find(Role.class, 1);
		Role role2 = entityManager.find(Role.class, 1);
	}
}

事务在service层处理,共享同一个session可以使用一级缓存

Hibernate: select role0_.id as id1_11_0_, role0_.en_name as en_name2_11_0_, role0_.name as name3_11_0_ from t_role role0_ where role0_.id=?

声明式、编程式

  • 声明式事务:在SpringBoot中声明式事务最常见,就是把需要事务的方法用@Transactional标注一下就行了,这个一般用在Service层。标注后该方法就具备了事务的能力,出错了会自动回滚。
  • 编程式事务:在有些场景下,我们需要获取事务的状态,是执行成功了还是失败回滚了,那么使用声明式事务就不够用了,需要编程式事务

https://blog.csdn.net/fzy629442466/article/details/103458630

public class TransactionManagerConfig implements TransactionManagementConfigurer {
 
    @Resource(name="txManager1")
    private PlatformTransactionManager txManager1;
 
    // 创建事务管理器1
    @Bean(name = "txManager1")
    public PlatformTransactionManager txManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
    /**     没有引用spring-boot-starter-data-jpa 依赖
    // 创建事务管理器2
    @Bean(name = "txManager2")
    public PlatformTransactionManager txManager2(EntityManagerFactory factory) {
        return new JpaTransactionManager(factory);
    }
     */
    //其返回值代表在拥有多个事务管理器的情况下默认使用的事务管理
    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        return txManager1;
    }
}
    @Transactional(value="txManager1")
    @Override
    public User addUser(User user) {
        
        userMapper.insert(user);
        int i = 1 / 0;
        return user;
    }

自定义声明事务

自定义注解接口

import java.lang.annotation.*;
/**
 * 注解类
 */
@Target(ElementType.METHOD)             //定义注解用在方法上
@Retention(RetentionPolicy.RUNTIME)     //运行时注解
@Documented
public @interface CustomTransaction {
    String value() default "";
}

写事务类

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
@Component
@Scope(value = "prototype")
public class TransactionUtils {
    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;
    /**
     *初始化创建TransactionStatus对象
     * @return
     */
    public TransactionStatus init(){
        System.out.println("创建事务了...");
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
        return transactionStatus;
    }
    /**
     * 提交事务
     * @param transactionStatus
     */
    public void commit(TransactionStatus transactionStatus){
        System.out.println("提交事务...");
        dataSourceTransactionManager.commit(transactionStatus);
    }
    public void rollback(TransactionStatus transactionStatus){
        System.out.println("事务回滚了....");
        dataSourceTransactionManager.rollback(transactionStatus);
    }
}

写切面类

import io.tianma.common.annotation.CustomTransaction;
import io.tianma.common.utils.TransactionUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import java.lang.reflect.Method;
@Aspect
@Component
public class CustomTransactionAspect {
    @Autowired
    TransactionUtils transactionUtils;
    /**
     * 选择切面的注解CustomTransaction
     */
    @Pointcut("@annotation(io.tianma.common.annotation.CustomTransaction)")
    public void transactionPointCut() {
    }
    /**
     * 方法增强@Arounbd
     * @param point
     */
    @Around("transactionPointCut()")
    public void around(ProceedingJoinPoint point){
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();//获取到方法对象
        //获取到注解类
        CustomTransaction annotation = method.getAnnotation(CustomTransaction.class);
        if(annotation != null){
            System.out.println(annotation.value());//打印注解上value的内容
        }
        //请求的类名以及方法名
        String className = point.getTarget().getClass().getName();
        String methodName = signature.getName();
        System.out.println("执行的方法为:" + className + "." + methodName + "()");
        //开启事务
        TransactionStatus transactionStatus = transactionUtils.init();
        try {
            //执行方法
            point.proceed();
            //执行成功提交事务
            transactionUtils.commit(transactionStatus);
        } catch (Throwable throwable) {
            //执行方法出错则回滚事务
            transactionUtils.rollback(transactionStatus);
        }
    }
}

项目service

 @Override
   @CustomTransaction("新增用户开启事务")
   public void saveUser() {
      SysUserEntity user = new SysUserEntity();
      user.setUserId("D123456");
      user.setName("张三");
      user.setCreateUserId("D123456");
      user.setCreateTime(new Date());
      this.save(user);
//    System.out.println(1/0);
      SysUserRoleEntity sysUserRoleEntity = new SysUserRoleEntity();
      sysUserRoleEntity.setRoleId(123456L);
      sysUserRoleEntity.setUserId("123456");
      sysUserRoleService.save(sysUserRoleEntity);
   }

源码解读

org.hibernate.loader.org.hibernate.loader

   List result = this.getResultFromQueryCache(session, queryParameters, querySpaces, resultTypes, queryCache, key);
        if (result == null) {
            result = this.doList(session, queryParameters, key.getResultTransformer());
            this.putResultInQueryCache(session, queryParameters, resultTypes, queryCache, key, result);
        }

参考