EE颠覆者第八章 2 事务和缓存

声明式事务

事务机制

提供接口,不同的数据库访问技术使用不同的接口实现

    @Bean
    public PlatformTransactionManager transactionManager(){
        JpaTransactionManager t=new JpaTransactionManager();
        t.setDataSource(dataSource());
        return t;
    }
        new DataSourceTransactionManager(); jdbc
        new JpaTransactionManager(); jpa
        new HibernateTransactionManager(); hibernate
        new JdoTransactionManager(); jdo
        new JtaTransactionManager(); 分布式事务

声明式事务

即:使用注解来选择需要使用事务的方法

@Transactional #表明该方法需要一个事务

也可以注解在类上,此类的所有public方法都是开启事务的。如果同时开启,则方法级别覆盖类级别的。

注解方法在被调用的时候,开启一个新的事务,无异常运行结束后,提交这个事务

@Configuration
@EnableTransactionManagement //开启声明式注解

simpleJpaRepository 在类级别定义了 @Transactional(readOnly = true)

在save,delete相关的操作重写了 @Transactional,此时 readOney=false

默认为false,指定当前事务是否是 只读事务

@Transactional(rollbackFor={IllegalArgumentException.class}) 
指定哪个或者那些异常可以引起事务回滚

spring Boot的事务支持

JDBC springBoot为我们定义了

    @Bean
    @ConditionalOnMissingBean //bean不存在就创建
    @ConditionalOnBean({DataSource.class})//当dataSourrce存在
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(this.dataSource);
    }

使用JPA的时候

    @Bean
    @ConditionalOnMissingBean({PlatformTransactionManager.class}) //当这个类没有配置的时候
    public PlatformTransactionManager transactionManager() {
        return new JpaTransactionManager();
    }

自动开启注解事务

@Configuration 配置
//存在这些类才配置
@ConditionalOnClass({TransactionTemplate.class, PlatformTransactionManager.class})
//判断这个类是单例的
@ConditionalOnSingleCandidate(PlatformTransactionManager.class)
 //自动配置,在这些类后面
@AutoConfigureAfter({JtaAutoConfiguration.class, JpaBaseConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class})
public class TransactionAutoConfiguration {
}

所以在实战中不需要 @TransactionAutoConfiguration

事务实战

pom

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
			<dependency>
			<groupId>com.oracle</groupId>
			<artifactId>ojdbc6</artifactId>
			<version>11.2.0.2.0</version>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

实体类

@Entity
public class Person {
	@Id 
	@GeneratedValue
	private Long id;
	
	private String name;
	
	private Integer age;
	
	private String address;
	
} //get set 无参 全参 

dao

public interface PersonRepository extends JpaRepository<Person, Long> {
}

service

public interface DemoService {
	public Person savePersonWithRollBack(Person person);
	public Person savePersonWithoutRollBack(Person person);
}

@Service
public class DemoServiceImpl implements DemoService {
	@Autowired
	PersonRepository personRepository; //1
	
	@Transactional(rollbackFor={IllegalArgumentException.class}) //2
	public Person savePersonWithRollBack(Person person){
		Person p =personRepository.save(person);

		if(person.getName().equals("汪云飞")){
			throw new IllegalArgumentException("汪云飞已存在,数据将回滚"); //3
		}
		return p;
	}

	@Transactional(noRollbackFor={IllegalArgumentException.class}) //4
	public Person savePersonWithoutRollBack(Person person){
		Person p =personRepository.save(person);
		
		if(person.getName().equals("汪云飞")){
			throw new IllegalArgumentException("汪云飞虽已存在,数据将不会回滚");
		}
		return p;
	}
}

rollbackFor 属性,数据回滚

noRollbackFor属性,数据不回滚

action

@RestController
public class MyController {
	@Autowired
	DemoService demoService;
	
	@RequestMapping("/rollback")
	public Person rollback(Person person){ //1
		return demoService.savePersonWithRollBack(person);
	}
	
	@RequestMapping("/norollback")
	public Person noRollback(Person person){//2
		return demoService.savePersonWithoutRollBack(person);
	}

}


@SpringBootApplication
public class Ch84Application {
    public static void main(String[] args) {
        SpringApplication.run(Ch84Application.class, args);
    }
}

application.properties

spring.datasource.driverClassName=oracle.jdbc.OracleDriver
spring.datasource.url=jdbc\:oracle\:thin\:@localhost\:1521\:xe
spring.datasource.username=boot
spring.datasource.password=boot

#1
spring.jpa.hibernate.ddl-auto=update
#2
spring.jpa.show-sql=true


spring.jackson.serialization.indent_output=true

数据缓存Cache

重复地获取相同的数据的时候,

我们一次又一次的请求数据库 或者 远程服务,导致大量的时间耗费在数据库查询或者远程方法调用上

CacheManager 用来统一不同的接口,是 各种缓存技术抽象接口。

    @Bean
    public EhCacheCacheManager cacheCacheManager(CacheManager ehCacheCacheManager){
        return new EhCacheCacheManager(ehCacheCacheManager);
    }

声明式缓存注解

@Cach eable ,先查看缓存中是否有数据,如果有数据,直接返回数据。 如果没有调用方法,并且放进缓存。使用放入的

@Cache Put ,无论怎样,都将方法的返回值,放到缓存中。和 Cach eable 保持一致。这个是放入

@Cache Evict, 将一条或多条数据从缓存中删除

@Caching , 可以通过@Caching 注解组合 多个注解策略在一个方法上。

开启注解:

@Configuration
@EnableCaching
public class AppConfig {
}

spring boot支持


org.springframework.boot.autoconfigure.cache;

EhCacheCacheConfiguration EhCacheCacheManager
GenericCacheConfiguration 对应:SimpleCacheManager。GenericCache配置的Simple
GuavaCacheConfiguration  GuavaCacheManager
HazelcastCacheConfiguration  HazelcastCacheManager
InfinispanCacheConfiguration infinispanCacheManager
JCacheCacheConfiguration JCacheCacheManager
NoOpCacheConfiguration  NoOpCacheManager 不使用
RedisCacheConfiguration RedisCacheManager
SimpleCacheConfiguration ConcurrentMapCacheManager simple下配置的是concurrentMap。默认值
        new SimpleCacheManager();  Collection来存储缓存,测试用的
        new ConcurrentMapCacheManager();  ConcurrentMap当做缓存
        new NoOpCacheManager(); 测试,不使用 
        new EhCacheCacheManager();  EhCacheCache
        new GuavaCacheManager(); 谷歌的GuavaCache
        new HazelcastCacheManager(); 无法new, Hazelcast
        new JCacheCacheManager(); Apache jcs的 JCacheCache
        new RedisCacheManager(); 无法new

spring.cache前缀

spring.cache.type=redis

public enum CacheType {

	/**
	 * Generic caching using 'Cache' beans from the context.
	 */
	GENERIC,

	/**
	 * EhCache backed caching.
	 */
	EHCACHE,

	/**
	 * Hazelcast backed caching
	 */
	HAZELCAST,

	/**
	 * Infinispan backed caching.
	 */
	INFINISPAN,

	/**
	 * JCache (JSR-107) backed caching.
	 */
	JCACHE,

	/**
	 * Redis backed caching.
	 */
	REDIS,

	/**
	 * Guava backed caching.
	 */
	GUAVA,

	/**
	 * Simple in-memory caching.
	 */
	SIMPLE,

	/**
	 * No caching.
	 */
	NONE;

}
spring:
  cache:
    type: redis
    cache-names: myCache #程序启动时候,缓存名称
    ehcache:
      config: ehcache.xml #配置文件的路径
    hazelcast:
      config: ehcache.xml
    infinispan:
      config: ehcache.xml
    jcache:
      config: ehcache.xml
      provider: #xxx ,当有多个jcache实现在路径中的时候,指定jcache实现
    guava:
      spec: #guava specs

只需要在项目中导入相关缓存技术的包,并且配置类使用 @EnableCaching开户缓存即可。

缓存实战

pom

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-cache</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		
		<dependency>
			<groupId>net.sf.ehcache</groupId>
			<artifactId>ehcache</artifactId>
		</dependency>
		<!--  
		<dependency>
			<groupId>com.google.guava</groupId>
			<artifactId>guava</artifactId>
			<version>18.0</version>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-redis</artifactId>
		</dependency>
		-->
		<dependency>
			<groupId>com.oracle</groupId>
			<artifactId>ojdbc6</artifactId>
			<version>11.2.0.2.0</version>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

实体类 ,启动类,配置文件,dao

@Entity
public class Person {
	@Id 
	@GeneratedValue
	private Long id;
	
	private String name;
	
	private Integer age;
	
	private String address;
	}//get set 无参构造,全参数构造
	
	
@SpringBootApplication
@EnableCaching //记得要开启缓存
public class Ch85Application {

    public static void main(String[] args) {

        SpringApplication.run(Ch85Application.class, args);
    }
    
}

spring.datasource.driverClassName=oracle.jdbc.OracleDriver
spring.datasource.url=jdbc\:oracle\:thin\:@192.168.31.183\:49161\:xe
spring.datasource.username=system
spring.datasource.password=oracle

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true


spring.jackson.serialization.indent_output=true
    
    
    
public interface PersonRepository extends JpaRepository<Person, Long> {
}
	

service

public interface DemoService {
	public Person save(Person person);
	
	public void remove(Long id);
	
	public Person findOne(Person person);

}



@Service
public class DemoServiceImpl implements DemoService {
	
	@Autowired
	PersonRepository personRepository;

	@Override
	@CachePut(value = "people", key = "#person.id") //放入
	public Person save(Person person) {
		Person p = personRepository.save(person);
		System.out.println("为id、key为:"+p.getId()+"数据做了缓存");
		return p;
	}

	@Override
	@CacheEvict(value = "people")//2 删除
	public void remove(Long id) {
		System.out.println("删除了id、key为"+id+"的数据缓存");
		//这里不做实际删除操作
	}

	@Override
	@Cacheable(value = "people", key = "#person.id")//3 使用
	public Person findOne(Person person) {
		Person p = personRepository.findOne(person.getId());
		System.out.println("为id、key为:"+p.getId()+"数据做了缓存");
		return p;
	}

}

如果没有指定key,则方法参数作为key,保存到缓存中

控制器

@RestController
public class CacheController {
	@Autowired
	DemoService demoService;
	
	@RequestMapping("/put")
	public Person put(Person person){
		return demoService.save(person);
	}

	@RequestMapping("/able")
	public Person cacheable(Person person){
		return demoService.findOne(person);
	}
	
	@RequestMapping("/evit")
	public String  evit(Long id){
		 demoService.remove(id);
		 return "ok";
	}
	
}

配置文件和测试

src/main/resources/ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<cache name="people" maxElementsInMemory="1000" />
</ehcache>
http://localhost:8080/able?id=22  //两次访问,第二次压根就不执行service代码,就返回结果了
http://localhost:8080/put?name=汪云飞2&age=24  //返回了一个ID
http://localhost:8080/able?id=35 //使用返回的ID查询,也是直接返回结果

http://localhost:8080/evit?id=35 //删除了id、key为35的数据缓存
http://localhost:8080/able?id=35 //在此访问,才会查询数据库

切换缓存技术:

ehcache , 切换成 guava缓存

切换成redis:

spring-boot-starter-redis

boot将会为我们配置redisCacheManager,以及redisTemplate的bean

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值