Spring Boot 整合mybatis 用Redis做二級快取
阿新 • • 發佈:2018-12-17
一:整合druid資料來源
一:導包
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
二:配置
用的是druid的連線池,jpa的自動建表,mytabis框架
spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/springboot username: root password: root jpa: hibernate: ddl-auto: update show-sql: true mybatis: type-aliases-package: com.tom.bean mapper-locations: classpth:mapper/*mapper.xml
druid的額外配置
# 初始化大小,最小,最大 spring.datasource.initialSize=5 spring.datasource.minIdle=5 spring.datasource.maxActive=20 # 配置獲取連線等待超時的時間 spring.datasource.maxWait=60000 # 配置間隔多久才進行一次檢測,檢測需要關閉的空閒連線,單位是毫秒 spring.datasource.timeBetweenEvictionRunsMillis=60000 # 配置一個連線在池中最小生存的時間,單位是毫秒 spring.datasource.minEvictableIdleTimeMillis=300000 # 校驗SQL,Oracle配置 spring.datasource.validationQuery=SELECT 1 FROM DUAL,如果不配validationQuery項,則下面三項配置無用 spring.datasource.validationQuery=SELECT 'x' spring.datasource.testWhileIdle=true spring.datasource.testOnBorrow=false spring.datasource.testOnReturn=false # 開啟PSCache,並且指定每個連線上PSCache的大小 spring.datasource.poolPreparedStatements=true spring.datasource.maxPoolPreparedStatementPerConnectionSize=20 # 配置監控統計攔截的filters,去掉後監控介面sql無法統計,'wall'用於防火牆 spring.datasource.filters=stat,wall,log4j # 通過connectProperties屬性來開啟mergeSql功能;慢SQL記錄 spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 # 合併多個DruidDataSource的監控資料 spring.datasource.useGlobalDataSourceStat=true
三:Mapper,Service,Controller
bean,用的自動建表
@Entity
public class teacher implements Serializable{
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String name;
private int age;
...
}
mapper,暫時只寫兩個方法
@Mapper public interface teachMapper { @Insert("insert into teacher values(null,#{age},#{name})") public void save(teacher t); @Select("select * from teacher where id=#{id}") public teacher getById(int id); }
service
@Service
public class teachService {
@Autowired
private teachMapper tm;
public teacher getById(int id) {
return tm.getById(id);
}
public void save(teacher t) {
tm.save(t);
}
}
Controller
@RestController
@RequestMapping("/teacher")
public class teachController {
@Autowired
private teachService ts;
@GetMapping("/{id}")
public teacher get(@PathVariable("id") int id) {
return ts.getById(id);
}
@PostMapping("/save")
public String save(teacher t) {
ts.save(t);
return "儲存成功";
}
}
四:druid配置
用druid的原因:一個因為聽說它效能很強,另一個主要的原因為可以進行實時監控
@WebFilter(filterName="druidWebStatFilter",urlPatterns="/*",
initParams={
@WebInitParam(name="exclusions",value="*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*")// 忽略資源
})
public class DruidStatFilter extends WebStatFilter {
}
@SuppressWarnings("serial")
@WebServlet(urlPatterns = "/druid/*",
initParams = { @WebInitParam(name = "allow", value = "127.0.0.1"), // IP白名單
@WebInitParam(name = "deny", value = "192.168.0.0"), // IP黑名單 (存在共同時,deny優先於allow)
@WebInitParam(name = "loginUsername", value = "admin"), // 使用者名稱
@WebInitParam(name = "loginPassword", value = "admin"), // 密碼
@WebInitParam(name = "resetEnable", value = "false")// 禁用HTML頁面上的“Reset All”功能
})
public class DruidStatViewServlet extends StatViewServlet {
}
最後,在啟動類上面加上@ServletComponentScan
@SpringBootApplication
//注意要加上@ServletComponentScan註解,否則Servlet無法生效
@ServletComponentScan
public class TomApplication {
public static void main(String[] args) {
SpringApplication.run(TomApplication.class, args);
}
}
簡直優秀。
二:將Redis作為mysql的二級快取
配置Redis
spring:
redis:
host: localhost
port: 6379
database: 1
jedis:
pool:
max-idle: 8
min-idle: 1
max-active: 8
max-wait: -1
接下來的步驟:①開啟mybatis的二級快取 ②重寫快取類 ③將mybatis的快取替換為們重寫的
重點:我們重寫mybatis的cache類,它只會對配置檔案型別的對映檔案起作用
<cache type=“我們重寫的cache類”/>
主要的作用如下:
1.所有在對映檔案裡的 select 語句都將被快取。 2.所有在對映檔案裡 insert,update 和 delete 語句會清空快取。 3.快取使用“最近很少使用”演算法來回收 4.快取不會被設定的時間所清空。
一:開啟二級快取,配置中加一條就好
mybatis:
configuration:
cache-enabled: true
二:重寫快取類
這裡也有一個問題,由於cache不是容器中的類,我們需要獲得applicationContext
@Component
public class ApplicationContextHolder implements ApplicationContextAware{
private static ApplicationContext applicationContext;
/**
* 實現ApplicationContextAware介面的context注入函式, 將其存入靜態變數.
*/
public void setApplicationContext(ApplicationContext applicationContext) {
ApplicationContextHolder.applicationContext = applicationContext; // NOSONAR
}
/**
* 取得儲存在靜態變數中的ApplicationContext.
*/
public static ApplicationContext getApplicationContext() {
checkApplicationContext();
return applicationContext;
}
/**
* 從靜態變數ApplicationContext中取得Bean, 自動轉型為所賦值物件的型別.
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
checkApplicationContext();
return (T) applicationContext.getBean(name);
}
/**
* 從靜態變數ApplicationContext中取得Bean, 自動轉型為所賦值物件的型別.
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(Class<T> clazz) {
checkApplicationContext();
return (T) applicationContext.getBeansOfType(clazz);
}
/**
* 清除applicationContext靜態變數.
*/
public static void cleanApplicationContext() {
applicationContext = null;
}
private static void checkApplicationContext() {
if (applicationContext == null) {
throw new IllegalStateException("applicaitonContext未注入,請在applicationContext.xml中定義SpringContextHolder");
}
}
}
重寫快取類
public class RedisCache implements Cache {
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private final String id; // cache instance id
private RedisTemplate redisTemplate;
private static final long EXPIRE_TIME_IN_MINUTES = 30; // redis過期時間
public RedisCache(String id) {
if (id == null) {
throw new IllegalArgumentException("Cache instances require an ID");
}
this.id = id;
}
@Override
public String getId() {
return id;
}
/**
* Put query result to redis
*
* @param key
* @param value
*/
@Override
@SuppressWarnings("unchecked")
public void putObject(Object key, Object value) {
RedisTemplate redisTemplate = getRedisTemplate();
ValueOperations opsForValue = redisTemplate.opsForValue();
opsForValue.set(key, value, EXPIRE_TIME_IN_MINUTES, TimeUnit.MINUTES);
System.out.println("放入結果到快取");
}
/**
* Get cached query result from redis
*
* @param key
* @return
*/
@Override
public Object getObject(Object key) {
RedisTemplate redisTemplate = getRedisTemplate();
ValueOperations opsForValue = redisTemplate.opsForValue();
System.out.println("獲取結果從快取");
return opsForValue.get(key);
}
/**
* Remove cached query result from redis
*
* @param key
* @return
*/
@Override
@SuppressWarnings("unchecked")
public Object removeObject(Object key) {
RedisTemplate redisTemplate = getRedisTemplate();
redisTemplate.delete(key);
System.out.println("從快取刪除了");
return null;
}
/**
* Clears this cache instance
*/
@Override
public void clear() {
RedisTemplate redisTemplate = getRedisTemplate();
redisTemplate.execute((RedisCallback) connection -> {
connection.flushDb();
return null;
});
System.out.println("清空快取");
}
@Override
public int getSize() {
return 0;
}
@Override
public ReadWriteLock getReadWriteLock() {
return readWriteLock;
}
private RedisTemplate getRedisTemplate() {
if (redisTemplate == null) {
redisTemplate = ApplicationContextHolder.getBean("redisTemplate");
}
return redisTemplate;
}
}
我在對映檔案中寫了增,刪,查3個方法
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.tom.mapper.teachMapper">
<cache type="com.tom.redisConfig.RedisCache"/>
<select id="getAll" resultType="teacher">
select * from teacher
</select>
<select id="getById" resultType="teacher">
select * from teacher where id=#{id}
</select>
<insert id="save">
insert into teacher values(null,#{age},#{name})
</insert>
<delete id="delete">
delete from teacher where id=#{id}
</delete>
</mapper>
OK!!讓我看一下效果
結果為:select會新增資料到redis,insert,update,delete會清空快取
但是這樣子好像有點坑了,除select外的操作都要清空快取,有待研究