本章知识点:Spring Data JPA,Spring Boot 使用Mysql,Spring MVC,EHCache,Spring Cache等(其中@Cacheable请看上一节的理论知识),具体分如下几个步骤:
步骤 | 描述 |
1 | 新建Maven Java Project |
2 | 在pom.xml中加入依赖包 |
3 | 编写Spring Boot启动类; |
4 | 配置application.properties; |
5 | 编写缓存配置类以及ehcache.xml配置文件 |
6 | 编写DemoInfo实体类进行测试; |
7 | 编写持久类DemoInfoRepository; |
8 | 编写处理类DemoInfoService; |
9 | 编写DemoInfoController测试类;运行测试 |
接下来是具体实现
1)新建Maven Java Project
新建一个工程名为spring-boot-ehcache的maven java project。
(2)在pom.xml中加入依赖包
在pom.xml文件中加入相应的依赖包,Spring Boot父节点依赖包;spring boot web支持;缓存依赖spring-context-support;集成ehcache需要的依赖;JPA操作数据库;mysql 数据库驱动,具体pom.xml文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
< project xmlns = "http://maven.apache.org/POM/4.0.0" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" >
< modelVersion >4.0.0 modelVersion >
< groupId >com.kfit groupId >
< artifactId >spring-boot-ehcache artifactId >
< version >0.0.1-SNAPSHOT version >
< packaging >jar packaging >
< name >spring-boot-ehcache name >
< url >http://maven.apache.org url >
< properties >
< project.build.sourceEncoding >UTF-8 project.build.sourceEncoding >
< java.version >1.8 java.version >
properties >
< parent >
< groupId >org.springframework.boot groupId >
< artifactId >spring-boot-starter-parent artifactId >
< version >1.3.3.RELEASE version >
parent >
< dependencies >
< dependency >
< groupId >junit groupId >
< artifactId >junit artifactId >
< scope >test scope >
dependency >
< dependency >
< groupId >org.springframework.boot groupId >
< artifactId >spring-boot-starter-web artifactId >
dependency >
< dependency >
< groupId >org.springframework groupId >
< artifactId >spring-context-support artifactId >
dependency >
< dependency >
< groupId >net.sf.ehcache groupId >
< artifactId >ehcache artifactId >
dependency >
< dependency >
< groupId >org.springframework.boot groupId >
< artifactId >spring-boot-starter-data-jpa artifactId >
dependency >
< dependency >
< groupId >mysql groupId >
< artifactId >mysql-connector-java artifactId >
dependency >
< dependency >
< groupId >org.springframework.boot groupId >
< artifactId >spring-boot-starter-test artifactId >
< scope >test scope >
dependency >
dependencies >
project >
|
3)编写Spring Boot启动类(com.kfit.App.java);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package com.kfit;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
*
*
* @SpringBootApplication申明让spring boot自动给程序进行必要的配置,
*
@SpringBootApplication
等待于:
@Configuration
@EnableAutoConfiguration
@ComponentScan
*
*
* @version v.0.1
*/
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App. class , args);
}
}
|
(4)配置application.properties;
在application.properties中主要配置数据库连接和JPA的基本配置,具体如下:
Src/main/resouces/application.properties:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
########################################################
###datasource ,mysql数据库连接配置
########################################################
spring.datasource.url = jdbc:mysql: //localhost:3306/test
spring.datasource.username = root
spring.datasource.password = root
spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.max-active= 20
spring.datasource.max-idle= 8
spring.datasource.min-idle= 8
spring.datasource.initial-size= 10
########################################################
### Java Persistence Api ,JPA自动建表操作配置
########################################################
# Specify the DBMS
spring.jpa.database = MYSQL
# Show or not log for each sql query
spring.jpa.show-sql = true
# Hibernate ddl auto (create, create-drop, update)
spring.jpa.hibernate.ddl-auto = update
# Naming strategy
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
# stripped before adding them to the entity manager)
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
|
5)编写缓存配置类以及ehcache.xml配置文件:
这个类主要是注册缓存管理对象EhCacheCacheManager、缓存工厂对象EhCacheManagerFactoryBean,具体代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
package com.kfit.config;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
/**
* 缓存配置.
*
* @version v.0.1
*/
@Configuration
@EnableCaching //标注启动缓存.
public class CacheConfiguration {
/**
* ehcache 主要的管理器
* @param bean
* @return
*/
@Bean
public EhCacheCacheManager ehCacheCacheManager(EhCacheManagerFactoryBean bean){
System.out.println( "CacheConfiguration.ehCacheCacheManager()" );
return new EhCacheCacheManager(bean.getObject());
}
/*
* 据shared与否的设置,
* Spring分别通过CacheManager.create()
* 或new CacheManager()方式来创建一个ehcache基地.
*
* 也说是说通过这个来设置cache的基地是这里的Spring独用,还是跟别的(如hibernate的Ehcache共享)
*
*/
@Bean
public EhCacheManagerFactoryBean ehCacheManagerFactoryBean(){
System.out.println( "CacheConfiguration.ehCacheManagerFactoryBean()" );
EhCacheManagerFactoryBean cacheManagerFactoryBean = new EhCacheManagerFactoryBean ();
cacheManagerFactoryBean.setConfigLocation ( new ClassPathResource( "conf/ehcache.xml" ));
cacheManagerFactoryBean.setShared( true );
return cacheManagerFactoryBean;
}
}
|
在src/main/resouces/conf下编写ehcache.xml配置文件,当然这个文件你可以放在其它目录下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
xml version = "1.0" encoding = "UTF-8" ?>
< ehcache xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation = "http://ehcache.org/ehcache.xsd"
updateCheck = "false" >
< diskStore path = "java.io.tmpdir/Tmp_EhCache" />
< defaultCache
eternal = "false"
maxElementsInMemory = "1000"
overflowToDisk = "false"
diskPersistent = "false"
timeToIdleSeconds = "0"
timeToLiveSeconds = "600"
memoryStoreEvictionPolicy = "LRU" />
< cache
name = "demo"
eternal = "false"
maxElementsInMemory = "100"
overflowToDisk = "false"
diskPersistent = "false"
timeToIdleSeconds = "0"
timeToLiveSeconds = "300"
memoryStoreEvictionPolicy = "LRU" />
ehcache >
|
(6)编写DemoInfo实体类进行测试;
在com.kfit.bean下编写DemoInfo实体类进行缓存测试:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
package com.kfit.bean;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
/**
* 测试实体类.
* @version v.0.1
*/
@Entity
public class DemoInfo {
@Id @GeneratedValue
private longid; //主键.
private String name; //名称;
private String pwd; //密码;
private intstate;
public long getId() {
returnid;
}
public void setId(longid) {
this .id = id;
}
public String getName() {
returnname;
}
publicvoid setName(String name) {
this .name = name;
}
public String getPwd() {
returnpwd;
}
public void setPwd(String pwd) {
this .pwd = pwd;
}
public int getState() {
returnstate;
}
public void setState(intstate) {
this .state = state;
}
@Override
public String toString() {
return "DemoInfo [id=" + id + ", name=" + name + ", pwd=" + pwd + ", state=" + state + "]" ;
}
}
|
(7)编写持久类DemoInfoRepository;
编写持久类DemoInfoRepository:
com.kfit.repository.DemoInfoRepository:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
package com.kfit.repository;
import org.springframework.data.repository.CrudRepository;
import com.kfit.bean.DemoInfo;
/**
* 操作数据库.
*
* @version v.0.1
*/
public interface DemoInfoRepository extends CrudRepository
}
|
(8)编写处理类DemoInfoService;
编写增删改查的方法,在这几个方法中都使用注解缓存,进行缓存的创建以及删除,修改等操作:
com.kfit.service.DemoInfoService:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package com.kfit.service;
import com.kfit.bean.DemoInfo;
import javassist.NotFoundException;
public interface DemoInfoService {
void delete(Long id);
DemoInfo update(DemoInfo updated) throws NotFoundException;
DemoInfo findById(Long id);
DemoInfo save(DemoInfo demoInfo);
}
|
com.kfit.service.impl.DemoInfoServiceImpl:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
package com.kfit.service.impl;
import javax.annotation.Resource;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import com.kfit.bean.DemoInfo;
import com.kfit.repository.DemoInfoRepository;
import com.kfit.service.DemoInfoService;
import javassist.NotFoundException;
@Service
public class DemoInfoServiceImpl implements DemoInfoService {
//这里的单引号不能少,否则会报错,被识别是一个对象;
public static final String CACHE_KEY = "'demoInfo'" ;
@Resource
private DemoInfoRepository demoInfoRepository;
/**
* value属性表示使用哪个缓存策略,缓存策略在ehcache.xml
*/
public static final String DEMO_CACHE_NAME = "demo" ;
/**
* 保存数据.
* @param demoInfo
*/
@CacheEvict (value=DEMO_CACHE_NAME,key=CACHE_KEY)
@Override
public DemoInfo save(DemoInfo demoInfo){
return demoInfoRepository.save(demoInfo);
}
/**
* 查询数据.
* @param id
* @return
*/
@Cacheable (value=DEMO_CACHE_NAME,key= "'demoInfo_'+#id" )
@Override
public DemoInfo findById(Long id){
System.err.println( "没有走缓存!" +id);
return demoInfoRepository.findOne(id);
}
/**
* http://www.mincoder.com/article/2096.shtml:
*
* 修改数据.
*
* 在支持Spring Cache的环境下,对于使用@Cacheable标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。@CachePut也可以声明一个方法支持缓存功能。与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。
@CachePut也可以标注在类上和方法上。使用@CachePut时我们可以指定的属性跟@Cacheable是一样的。
*
* @param updated
* @return
*
* @throws NotFoundException
*/
@CachePut (value = DEMO_CACHE_NAME,key = "'demoInfo_'+#updated.getId()" )
//@CacheEvict(value = DEMO_CACHE_NAME,key = "'demoInfo_'+#updated.getId()")//这是清除缓存.
@Override
public DemoInfo update(DemoInfo updated) throws NotFoundException{
DemoInfo demoInfo = demoInfoRepository.findOne(updated.getId());
if (demoInfo == null ){
thrownew NotFoundException( "No find" );
}
demoInfo.setName(updated.getName());
demoInfo.setPwd(updated.getPwd());
return demoInfo;
}
/**
* 删除数据.
* @param id
*/
@CacheEvict (value = DEMO_CACHE_NAME,key = "'demoInfo_'+#id" ) //这是清除缓存.
@Override
public void delete(Long id){
demoInfoRepository.delete(id);
}
}
|
(9)编写DemoInfoController测试类;
编写一个rest进行测试:
com.kfit.controller.DemoInfoController:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
package com.kfit.controller;
import javax.annotation.Resource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.kfit.bean.DemoInfo;
import com.kfit.service.DemoInfoService;
import javassist.NotFoundException;
@RestController
public class DemoInfoController {
@Resource
private DemoInfoService demoInfoService;
@RequestMapping ( "/test" )
public String test(){
//存入两条数据.
DemoInfo demoInfo = new DemoInfo();
demoInfo.setName( "张三" );
demoInfo.setPwd( "123456" );
DemoInfo demoInfo2 = demoInfoService.save(demoInfo);
//不走缓存.
System.out.println(demoInfoService.findById(demoInfo2.getId()));
//走缓存.
System.out.println(demoInfoService.findById(demoInfo2.getId()));
demoInfo = new DemoInfo();
demoInfo.setName( "李四" );
demoInfo.setPwd( "123456" );
DemoInfo demoInfo3 = demoInfoService.save(demoInfo);
//不走缓存.
System.out.println(demoInfoService.findById(demoInfo3.getId()));
//走缓存.
System.out.println(demoInfoService.findById(demoInfo3.getId()));
System.out.println( "============修改数据=====================" );
//修改数据.
DemoInfo updated = new DemoInfo();
updated.setName( "李四-updated" );
updated.setPwd( "123456" );
updated.setId(demoInfo3.getId());
try {
System.out.println(demoInfoService.update(updated));
} catch (NotFoundException e) {
e.printStackTrace();
}
//不走缓存.
System.out.println(demoInfoService.findById(updated.getId()));
return "ok" ;
}
}
|
(10)运行测试;
运行App.java进行测试,访问:http://127.0.0.1:8080/test 进行测试,主要是观察控制台的打印信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
Hibernate: insert into demo_info (name, pwd, state) values (?, ?, ?)
没有走缓存! 52
DemoInfo [id= 52 , name=张三, pwd= 123456 , state= 0 ]
DemoInfo [id= 52 , name=张三, pwd= 123456 , state= 0 ]
Hibernate: insert into demo_info (name, pwd, state) values (?, ?, ?)
没有走缓存! 53
DemoInfo [id= 53 , name=李四, pwd= 123456 , state= 0 ]
DemoInfo [id= 53 , name=李四, pwd= 123456 , state= 0 ]
============修改数据=====================
DemoInfo [id= 53 , name=李四-updated, pwd= 123456 , state= 0 ]
DemoInfo [id= 53 , name=李四-updated, pwd= 123456 , state= 0 ]
C:\Users\ADMINI~ 1 .ANG\AppData\Local\Temp\
Hibernate: insert into demo_info (name, pwd, state) values (?, ?, ?)
没有走缓存! 54
DemoInfo [id= 54 , name=张三, pwd= 123456 , state= 0 ]
DemoInfo [id= 54 , name=张三, pwd= 123456 , state= 0 ]
Hibernate: insert into demo_info (name, pwd, state) values (?, ?, ?)
没有走缓存! 55
DemoInfo [id= 55 , name=李四, pwd= 123456 , state= 0 ]
DemoInfo [id= 55 , name=李四, pwd= 123456 , state= 0 ]
============修改数据=====================
DemoInfo [id= 55 , name=李四-updated, pwd= 123456 , state= 0 ]
DemoInfo [id= 55 , name=李四-updated, pwd= 123456 , state= 0 ]
|