前言

使用关系型数据库的应用系统的性能瓶颈最终还是数据库。随着业务的迅速增长,数据量会不断增大,会逐渐暴露关系型数据库的弱点,性能会大幅度的降低

项目地址:https://github.com/AndyFlower/Spring-Boot-Learn/tree/master/spring-boot-dbup

一、使用Druid

Druid是一个关系型数据库连接池,它是阿里巴巴的一个开源项目。Druid支持所有JDBC兼容的数据库,包括,Oracle,MySql,Derby,PostgreSQL,SQL Server,H2等。Druid在监控、可扩展性、稳定性和性能方面具有明显的优势。通过Druid提供的监控功能,可以实时观察数据库连接池和SQL查询的工作状况。使用Druid连接池,在一定程度上可以提高数据库的访问性能。使用Druid连接池,在一定程度上可以提高数据库的访问性能。

1、配置Druid依赖

  1. <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
  2. <dependency>
  3. <groupId>com.alibaba</groupId>
  4. <artifactId>druid</artifactId>
  5. <version>1.0.29</version>
  6. </dependency>

2、使用XML配置

使用Spring开发框架时,XML配置是经常使用的一种配置方法,其中数据源配置就是使用XML配置的一种。使用Spring Boot框架也能使用XML配置,只要在程序入口使用一个注解即@ImportResource({"classpath:spring-datasource.xml"}),即可导入XML配置,但是Spring Boot更推荐使用application.properties或application.yum文件来进行配置

  1. server.port=80
  2. server.tomcat.uri-encoding=utf-8
  3.  
  4. spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
  5. spring.datasource.driver-class-name=com.mysql.jdbc.Driver
  6. spring.datasource.url=jdbc:mysql://localhost:3306/dev?characterEncoding=utf-8
  7. spring.datasource.username=root
  8. spring.datasource.password=123456
  9. #初始化大小
  10. spring.datasource.initial-size=5
  11. #最小
  12. spring.datasource.min-idle=5
  13. #最大
  14. spring.datasource.max-active=20
  15. #配置获取连接等待超时的时间
  16. spring.datasource.max-wait=60000
  17. #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
  18. spring.datasource.time-between-eviction-runs-millis=60000
  19. #配置一个连接在池中最小生存的时间,单位是毫秒
  20. spring.datasource.min-evictable-idle-time-millis=300000
  21. spring.datasource.validation-query=SELECT 1 FROM DUAL
  22. spring.datasource.test-while-idle=true
  23. spring.datasource.test-on-borrow=false
  24. spring.datasource.test-on-return=false
  25. #打开PSCache,并且指定每个连接上的PSCache的大小
  26. spring.datasource.pool-prepared-statements=true
  27. spring.datasource.max-pool-prepared-statement-per-connection-size=20
  28. #配置监控统计拦截的filters,去掉后监控界面sql无法统计 wall用于防火墙
  29. spring.datasource.filters=stat,wall,log4j
  30. spring.datasource.connection-properties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
  31.  
  32. spring.jpa.database=mysql
  33. spring.jpa.show-sql=true
  34. spring.jpa.hibernate.ddl-auto=update
  35. spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy
  36. spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
  37.  
  38. spring.redis.host=localhost
  39. spring.redis.port=6379
  40. spring.redis.pool.max-idle=8
  41. spring.redis.pool.min-idle=0
  42. spring.redis.pool.max-active=8
  43. spring.redis.pool.max-wait=-1

3、开启监控功能

开启Druid的监控功能可以在应用运行的过程中,通过监控提供的多维度数据来分析使用数据库的运行情况。从而调整程序设计,以优化数据库的访问性能。

设置访问连接地址为“/druid/*”,设定访问数据库的白名单和黑名单,即通过访问者的IP来控制访问员,增加了数据库的安全设置,还配置了用于登陆的用户名和密码。

  1. package com.slp.dbexpand;
  2.  
  3. import com.alibaba.druid.support.http.StatViewServlet;
  4. import com.alibaba.druid.support.http.WebStatFilter;
  5. import org.springframework.boot.context.embedded.FilterRegistrationBean;
  6. import org.springframework.boot.context.embedded.ServletRegistrationBean;
  7. import org.springframework.context.annotation.Bean;
  8. import org.springframework.context.annotation.Configuration;
  9.  
  10. /**
  11. * Created by sangliping on 2017/9/1.
  12. */
  13. @Configuration
  14. public class DruidConfiguration {
  15. @Bean
  16. public ServletRegistrationBean statViewServlet(){
  17. ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
  18. //白名单
  19. servletRegistrationBean.addInitParameter("allow","127.0.01");
  20. //IP黑名单(共同存在时,deny优先于allow)
  21. servletRegistrationBean.addInitParameter("deny","192.168.1.100");
  22. //登陆查看新的是账户密码
  23. servletRegistrationBean.addInitParameter("loginUsername","druid");
  24. servletRegistrationBean.addInitParameter("loginPassword","123456");
  25. //是否能够重置数据
  26. servletRegistrationBean.addInitParameter("resetEnable","false");
  27. return servletRegistrationBean;
  28. }
  29.  
  30. @Bean
  31. public FilterRegistrationBean statFilter(){
  32. FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
  33. //添加过滤规则
  34. filterRegistrationBean.addUrlPatterns("/*");
  35. //添加不需要忽略的格式信息
  36. filterRegistrationBean.addInitParameter("exclusions","*.js.*.gif,*.png,*.css,*.ico,/druid/*");
  37. return filterRegistrationBean;
  38. }
  39. }

4、扩展JPA实现

4.1首先创建一个接口,继承与JpaRepository,并将接口标记为@NoRepositoryBean以防被当做一般的Repository调用,该接口不仅扩展了原来的findOne、findAll、count等方法而且增加了deleteById、getEntityClass、nativeQuery4Map等方法,其中nativeQuery4Map用于执行原生的复杂的SQL查询语句。

  1. package com.slp.dbexpand.jpa.repository;
  2.  
  3. import com.slp.dbexpand.jpa.parameter.Operator;
  4. import com.slp.dbexpand.jpa.parameter.Predicate;
  5. import org.springframework.data.domain.Page;
  6. import org.springframework.data.domain.Pageable;
  7. import org.springframework.data.domain.Sort;
  8. import org.springframework.data.jpa.repository.JpaRepository;
  9. import org.springframework.data.repository.NoRepositoryBean;
  10.  
  11. import java.io.Serializable;
  12. import java.util.List;
  13. import java.util.Map;
  14. /**
  15. * Created by sangliping on 2017/9/1.
  16. */
  17. @NoRepositoryBean
  18. public interface ExpandJpaRepository <T, ID extends Serializable> extends JpaRepository<T,ID> {
  19. T findOne(String condition, Object... objects);
  20.  
  21. List<T> findAll(String condition, Object... objects);
  22.  
  23. List<T> findAll(Iterable<Predicate> predicates, Operator operator);
  24.  
  25. List<T> findAll(Iterable<Predicate> predicates, Operator operator, Sort sort);
  26.  
  27. Page<T> findAll(Iterable<Predicate> predicates, Operator operator, Pageable pageable);
  28.  
  29. long count(Iterable<Predicate> predicates, Operator operator);
  30.  
  31. List<T> findAll(String condition, Sort sort, Object... objects);
  32.  
  33. Page<T> findAll(String condition, Pageable pageable, Object... objects);
  34.  
  35. long count(String condition, Object... objects);
  36.  
  37. void deleteByIds(Iterable<ID> ids);
  38.  
  39. Class<T> getEntityClass();
  40.  
  41. List<Map<String,Object>> nativeQuery4Map(String sql);
  42.  
  43. Page<Map> nativeQuery4Map(String sql, Pageable pageable);
  44.  
  45. Object nativeQuery4Object(String sql);
  46. }
  1. package com.slp.dbexpand.jpa.repository;
  2.  
  3. import com.slp.dbexpand.jpa.Exception.DataException;
  4. import com.slp.dbexpand.jpa.parameter.Operator;
  5. import com.slp.dbexpand.jpa.parameter.Predicate;
  6. import org.hibernate.SQLQuery;
  7. import org.hibernate.transform.Transformers;
  8. import org.springframework.data.domain.Page;
  9. import org.springframework.data.domain.PageImpl;
  10. import org.springframework.data.domain.Pageable;
  11. import org.springframework.data.domain.Sort;
  12. import org.springframework.data.jpa.repository.query.QueryUtils;
  13. import org.springframework.data.jpa.repository.support.JpaEntityInformation;
  14. import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
  15.  
  16. import javax.persistence.*;
  17. import java.io.Serializable;
  18. import java.lang.reflect.Field;
  19. import java.util.*;
  20.  
  21. import static org.apache.commons.lang3.StringUtils.*;
  22.  
  23. /**
  24. * Created by sangliping on 2017/9/1.
  25. */
  26. public class ExpandJpaRepositoryImpl<T,ID extends Serializable> extends SimpleJpaRepository<T,ID> implements ExpandJpaRepository<T,ID> {
  27.  
  28. private final EntityManager entityManager;
  29. private final JpaEntityInformation<T, ?> entityInformation;
  30.  
  31. public ExpandJpaRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
  32. super(entityInformation, entityManager);
  33. this.entityManager = entityManager;
  34. this.entityInformation = entityInformation;
  35. }
  36.  
  37. @Override
  38. public T findOne(String condition, Object... values) {
  39. if(isEmpty(condition)){
  40. throw new NullPointerException("条件不能为空!");
  41. }
  42. T result = null;
  43. try {
  44. result = (T) createQuery(condition, values).getSingleResult();
  45. } catch (NoResultException e) {
  46. e.printStackTrace();
  47. }
  48. return result;
  49.  
  50. }
  51.  
  52. @Override
  53. public List<T> findAll(Iterable<Predicate> predicates, Operator operator) {
  54. return new JpqlQueryHolder(predicates,operator).createQuery().getResultList();
  55. }
  56.  
  57. @Override
  58. public List<T> findAll(Iterable<Predicate> predicates, Operator operator, Sort sort) {
  59. return new JpqlQueryHolder(predicates,operator,sort).createQuery().getResultList();
  60. }
  61.  
  62. @Override
  63. public Page<T> findAll(Iterable<Predicate> predicates, Operator operator, Pageable pageable) {
  64. if(pageable==null){
  65. return new PageImpl<T>((List<T>) findAll(predicates,operator));
  66. }
  67.  
  68. Long total = count(predicates,operator);
  69.  
  70. Query query = new JpqlQueryHolder(predicates,operator,pageable.getSort()).createQuery();
  71. query.setFirstResult(pageable.getOffset());
  72. query.setMaxResults(pageable.getPageSize());
  73.  
  74. List<T> content = total > pageable.getOffset() ? query.getResultList() : Collections.<T> emptyList();
  75.  
  76. return new PageImpl<T>(content, pageable, total);
  77. }
  78.  
  79. @Override
  80. public List<T> findAll(String condition, Object... objects) {
  81. return createQuery(condition, objects).getResultList();
  82. }
  83.  
  84. @Override
  85. public List<T> findAll(String condition, Sort sort, Object... objects) {
  86. return createQuery(condition, sort, objects).getResultList();
  87. }
  88.  
  89. @Override
  90. public Page<T> findAll(String condition, Pageable pageable, Object... objects) {
  91.  
  92. if(pageable==null){
  93. return new PageImpl<T>((List<T>) findAll(condition,objects));
  94. }
  95.  
  96. Long total = count(condition,objects);
  97.  
  98. Query query = createQuery(condition, pageable.getSort(), objects);
  99. query.setFirstResult(pageable.getOffset());
  100. query.setMaxResults(pageable.getPageSize());
  101.  
  102. List<T> content = total > pageable.getOffset() ? query.getResultList() : Collections.<T> emptyList();
  103.  
  104. return new PageImpl<T>(content, pageable, total);
  105. }
  106.  
  107. @Override
  108. public Page<T> findAll(Pageable pageable) {
  109. return this.findAll("", pageable);
  110. }
  111.  
  112. @Override
  113. public List<T> findAll(Iterable<ID> ids) {
  114. return this.findAll("x."+getIdName()+" in ?1",ids);
  115. }
  116.  
  117. @Override
  118. public long count(String condition, Object... objects) {
  119. return new JpqlQueryHolder(condition,objects).createCountQuery().getSingleResult();
  120. }
  121.  
  122. @Override
  123. public long count(Iterable<Predicate> predicates, Operator operator) {
  124. return new JpqlQueryHolder(predicates,operator).createCountQuery().getSingleResult();
  125. }
  126.  
  127. @Override
  128. public void deleteByIds(Iterable<ID> ids) {
  129. List<T> tlist = super.findAll(ids);
  130. super.deleteInBatch(tlist);
  131. }
  132.  
  133. @Override
  134. public Class<T> getEntityClass() {
  135. return entityInformation.getJavaType();
  136. }
  137.  
  138. public String getIdName(){
  139. Class<?> entityClass = getEntityClass();
  140. do{
  141. Field[] fields = entityClass.getDeclaredFields();
  142. for(Field field:fields){
  143. if(field.getAnnotation(Id.class)!=null){
  144. return field.getName();
  145. }
  146. }
  147. entityClass = entityClass.getSuperclass();
  148. }while (entityClass != Object.class);
  149. throw new DataException("未设置主键",DataException.noID);
  150. }
  151.  
  152. @Override
  153. public List<Map<String, Object>> nativeQuery4Map(String sql) {
  154. Query nativeQuery = entityManager.createNativeQuery(sql);
  155. nativeQuery.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
  156. return nativeQuery.getResultList();
  157. }
  158.  
  159. @Override
  160. public Page<Map> nativeQuery4Map(String sql, Pageable pageable) {
  161. Query nativeQuery = entityManager.createNativeQuery(sql);
  162. nativeQuery.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
  163. nativeQuery.setFirstResult(pageable.getOffset());
  164. nativeQuery.setMaxResults(pageable.getPageSize());
  165.  
  166. Query countNativeQuery = entityManager.createNativeQuery("select count(*) from ("+sql+") a");
  167. long total = Long.valueOf(String.valueOf(countNativeQuery.getSingleResult()));
  168.  
  169. return new PageImpl<Map>(nativeQuery.getResultList(),pageable,total);
  170. }
  171.  
  172. @Override
  173. public Object nativeQuery4Object(String sql) {
  174. Query nativeQuery = entityManager.createNativeQuery(sql);
  175.  
  176. List results=nativeQuery.getResultList();
  177. if(results==null || results.size()==0){
  178. return null;
  179. }
  180. try{
  181. if(results.size()>1){
  182. throw new RuntimeException("结果应当只有一个,但是发现了"+results.size()+"个。");
  183. }
  184. return results.get(0);
  185. }catch (NoResultException e){
  186. return null ;
  187. }
  188.  
  189. }
  190.  
  191. private TypedQuery createCountQuery(String condition, Object[] objects){
  192.  
  193. JpqlQueryHolder queryHolder = new JpqlQueryHolder(condition,objects);
  194.  
  195. return queryHolder.createCountQuery();
  196. }
  197.  
  198. /**
  199. * 声明entityClass的查询
  200. */
  201. private Query createQuery(String condition, Sort sort, Object[] objects) {
  202.  
  203. JpqlQueryHolder queryHolder = new JpqlQueryHolder(condition,sort,objects);
  204.  
  205. return queryHolder.createQuery();
  206. }
  207.  
  208. /**
  209. * 声明entityClass的查询
  210. */
  211. private Query createQuery(String condition, Object[] objects) {
  212. return createQuery(condition, null, objects);
  213. }
  214.  
  215. private class JpqlQueryHolder {
  216.  
  217. //别名
  218. private final String ALIAS = "x";
  219.  
  220. //QUERY ALL
  221. private final String FIND_ALL_QUERY_STRING = "from %s "+ALIAS;
  222.  
  223. //传入的condition 排除列表
  224. private final String[] IGNORE_CONSTAINS_CHARSEQUENCE = {"where","WHERE","from","FROM"};
  225.  
  226. private String condition = null;
  227. private Sort sort;
  228. private Object[] objects;
  229. private Iterable<Predicate> predicates;
  230. private Operator operator = Operator.AND;
  231.  
  232. private JpqlQueryHolder(Iterable<Predicate> predicates, Operator operator, Sort sort) {
  233. this.predicates = predicates;
  234. this.operator = operator;
  235. this.sort = sort;
  236. }
  237.  
  238. private JpqlQueryHolder(Iterable<Predicate> predicates , Operator operator ) {
  239. this.operator = operator;
  240. this.predicates = predicates;
  241. }
  242.  
  243. private JpqlQueryHolder(String condition, Sort sort, Object[] objects) {
  244. this(condition,objects);
  245. this.sort = sort;
  246. }
  247.  
  248. private JpqlQueryHolder(String condition, Object[] objects) {
  249.  
  250. if(startsWithAny(condition,IGNORE_CONSTAINS_CHARSEQUENCE)){
  251. throw new DataException("查询条件中只能包含WHERE条件表达式!",DataException.noPermission);
  252. }
  253. this.condition = trimToNull(condition);
  254. this.objects = objects;
  255. }
  256.  
  257. private Query createQuery(){
  258. StringBuilder sb = new StringBuilder();
  259. // select x from table
  260. sb.append(QueryUtils.getQueryString(FIND_ALL_QUERY_STRING, entityInformation.getEntityName()))
  261. //where
  262. .append(applyCondition());
  263.  
  264. Query query = entityManager.createQuery(QueryUtils.applySorting(sb.toString(), sort, ALIAS));
  265. applyQueryParameter(query);
  266. return query;
  267. }
  268.  
  269. private TypedQuery<Long> createCountQuery(){
  270. String ql = String.format(QueryUtils.COUNT_QUERY_STRING, ALIAS, "%s");
  271. ql = QueryUtils.getQueryString(ql, entityInformation.getEntityName());
  272. ql += applyCondition();
  273.  
  274. TypedQuery<Long> query = entityManager.createQuery(ql,Long.class);
  275. applyQueryParameter(query);
  276. return query;
  277. }
  278.  
  279. private List<String> map2Conditions(){
  280. if(predicates==null||!predicates.iterator().hasNext()){
  281. return new ArrayList<String>();
  282. }
  283. List<String> conditions = new ArrayList<String>();
  284.  
  285. Iterator<Predicate> iterator = predicates.iterator();
  286. int index = 0 ;
  287. while (iterator.hasNext()){
  288. Predicate predicate = iterator.next();
  289. if(predicate.getKey()==null){
  290. continue;
  291. }
  292. conditions.add(predicate.toCondition(String.valueOf(index)));
  293. index++ ;
  294. }
  295. return conditions;
  296. }
  297.  
  298. private String applyCondition(){
  299. List<String> conditions = map2Conditions();
  300. if(condition!=null) {
  301. conditions.add(condition);
  302. }
  303. condition = join(conditions, " " + operator.name() + " ");
  304. return isEmpty(condition)?"":" where "+condition;
  305. }
  306.  
  307. private void applyQueryParameter(Query query){
  308. if(objects!=null){
  309. int i = 0;
  310. for(Object value:objects){
  311. i++;
  312. query.setParameter(i,value);
  313. }
  314. }
  315. if(predicates!=null&&predicates.iterator().hasNext()){
  316. int index = 0 ;
  317. Iterator<Predicate> iterator = predicates.iterator();
  318. while (iterator.hasNext()){
  319. Predicate predicate = iterator.next();
  320. predicate.setParameter(query,String.valueOf(index));
  321. index++ ;
  322. }
  323. }
  324. }
  325. }
  326.  
  327. }

4.2、装配自定义的扩展接口

自定义的接口必须在程序启动的时候装配,才能正常使用。首先创建一个ExpandJpaRepositoryFactoryBean继承于JpaRepositoryFactoryBean,用于加载自定义的扩展接口,其中getTargetRepository返回自定义的接口实现ExpandJpaRepositoryImpl:

  1. package com.slp.dbexpand.jpa.repository;
  2.  
  3. import org.springframework.data.jpa.repository.JpaRepository;
  4. import org.springframework.data.jpa.repository.support.JpaEntityInformation;
  5. import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
  6. import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
  7. import org.springframework.data.repository.core.RepositoryMetadata;
  8. import org.springframework.data.repository.core.support.RepositoryFactorySupport;
  9.  
  10. import javax.persistence.EntityManager;
  11. import java.io.Serializable;
  12.  
  13. /**
  14. * Created by sangliping on 2017/9/1.
  15. */
  16. public class ExpandJpaRepositoryBean<R extends JpaRepository<T, ID>, T, ID extends Serializable>extends JpaRepositoryFactoryBean<R, T, ID> {
  17. protected RepositoryFactorySupport createRepositoryFactory(
  18. EntityManager entityManager) {
  19. return new ExpandJpaRepositoryFactory<T, ID>(entityManager);
  20. }
  21.  
  22. private static class ExpandJpaRepositoryFactory<T, ID extends Serializable>
  23. extends JpaRepositoryFactory {
  24.  
  25. private final EntityManager entityManager;
  26.  
  27. public ExpandJpaRepositoryFactory(EntityManager entityManager) {
  28.  
  29. super(entityManager);
  30. this.entityManager = entityManager;
  31. }
  32.  
  33. protected Object getTargetRepository(RepositoryMetadata metadata) {
  34. JpaEntityInformation<T, Serializable> entityInformation = (JpaEntityInformation<T, Serializable>) getEntityInformation(metadata.getDomainType());
  35. return new ExpandJpaRepositoryImpl<T, ID>(entityInformation, entityManager);
  36. }
  37.  
  38. protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
  39. return ExpandJpaRepositoryImpl.class;
  40. }
  41. }
  42. }

4.3在jpa配置类中通过@EnableJpaRepository加载定义的装配类ExpandJpaRepositoryFactoryBean

  1. package com.slp.dbexpand;
  2.  
  3. import com.slp.dbexpand.jpa.repository.ExpandJpaRepositoryBean;
  4. import org.springframework.boot.orm.jpa.EntityScan;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.context.annotation.Configuration;
  7. import org.springframework.core.Ordered;
  8. import org.springframework.core.annotation.Order;
  9. import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
  10. import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
  11. import org.springframework.transaction.annotation.EnableTransactionManagement;
  12.  
  13. /**
  14. * Created by sangliping on 2017/9/1.
  15. */
  16. @Order(Ordered.HIGHEST_PRECEDENCE)
  17. @Configuration
  18. @EnableTransactionManagement(proxyTargetClass = false)
  19. @EnableJpaRepositories(basePackages = "com.slp.repository",repositoryFactoryBeanClass = ExpandJpaRepositoryBean.class)
  20. @EntityScan(basePackages = "com.slp.entity")
  21. public class JpaConfiguration {
  22. @Bean
  23. PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor(){
  24. return new PersistenceExceptionTranslationPostProcessor();
  25. }
  26. }

4.3、使用Redis做缓存

在数据库使用中,数据查询是最大的性能开销。如果能借助Redis作为辅助缓存,将可以极大的提高数据库的访问性能。使用Redis做缓存,一方面可以调用,另一方面可以使用注解的方式调用。

值得注意的是,Redis是一个具有持久化功能的数据库系统,若使用默认配置,存取的数据就会永久的保存在磁盘中。如果只是使用Redis做缓存的话可以设定Redis保存数据的期限来实现,这样,过期的数据会自动清除。

1)使用spring cache注解

  1. package com.slp.dbexpand.jpa;
  2. import com.fasterxml.jackson.annotation.JsonAutoDetect;
  3. import com.fasterxml.jackson.annotation.PropertyAccessor;
  4. import com.fasterxml.jackson.databind.ObjectMapper;
  5. import org.springframework.cache.CacheManager;
  6. import org.springframework.cache.annotation.CachingConfigurerSupport;
  7. import org.springframework.cache.annotation.EnableCaching;
  8. import org.springframework.cache.interceptor.KeyGenerator;
  9. import org.springframework.context.annotation.Bean;
  10. import org.springframework.context.annotation.Configuration;
  11. import org.springframework.data.redis.cache.RedisCacheManager;
  12. import org.springframework.data.redis.connection.RedisConnectionFactory;
  13. import org.springframework.data.redis.core.RedisTemplate;
  14. import org.springframework.data.redis.core.StringRedisTemplate;
  15. import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
  16.  
  17. import java.lang.reflect.InvocationTargetException;
  18. import java.lang.reflect.Method;
  19. /**
  20. * Created by sangliping on 2017/9/1.
  21. */
  22. @Configuration
  23. @EnableCaching
  24. public class RedisConfig extends CachingConfigurerSupport{
  25. @Bean
  26. public KeyGenerator simpleKey(){
  27. return new KeyGenerator() {
  28. @Override
  29. public Object generate(Object target, Method method, Object... params) {
  30. StringBuilder sb = new StringBuilder();
  31. sb.append(target.getClass().getName()+":");
  32. for (Object obj : params) {
  33. sb.append(obj.toString());
  34. }
  35. return sb.toString();
  36. }
  37. };
  38. }
  39.  
  40. @Bean
  41. public KeyGenerator objectId(){
  42. return new KeyGenerator() {
  43. @Override
  44. public Object generate(Object target, Method method, Object... params){
  45. StringBuilder sb = new StringBuilder();
  46. sb.append(target.getClass().getName()+":");
  47. try {
  48. sb.append(params[0].getClass().getMethod("getId", null).invoke(params[0], null).toString());
  49. }catch (NoSuchMethodException no){
  50. no.printStackTrace();
  51. }catch(IllegalAccessException il){
  52. il.printStackTrace();
  53. }catch(InvocationTargetException iv){
  54. iv.printStackTrace();
  55. }
  56. return sb.toString();
  57. }
  58. };
  59. }
  60.  
  61. @Bean
  62. public CacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {
  63. RedisCacheManager manager = new RedisCacheManager(redisTemplate);
  64. manager.setDefaultExpiration(43200);//12小时
  65. return manager;
  66. }
  67.  
  68. @Bean
  69. public RedisTemplate<String, String> redisTemplate(
  70. RedisConnectionFactory factory) {
  71. StringRedisTemplate template = new StringRedisTemplate(factory);
  72. Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
  73. ObjectMapper om = new ObjectMapper();
  74. om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
  75. om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  76. jackson2JsonRedisSerializer.setObjectMapper(om);
  77. template.setValueSerializer(jackson2JsonRedisSerializer);
  78. template.afterPropertiesSet();
  79. return template;
  80. }
  81.  
  82. }

2)使用RedisTemplate

  1. package com.slp.redis;
  2. import com.google.gson.Gson;
  3. import com.google.gson.reflect.TypeToken;
  4. import com.slp.entity.User;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.data.redis.core.RedisTemplate;
  7. import org.springframework.stereotype.Repository;
  8. import org.springframework.util.StringUtils;
  9.  
  10. import java.util.List;
  11. import java.util.concurrent.TimeUnit;
  12. /**
  13. * Created by sangliping on 2017/9/1.
  14. */
  15. @Repository
  16. public class UserRedis {
  17. @Autowired
  18. private RedisTemplate<String, String> redisTemplate;
  19.  
  20. public void add(String key, Long time, User user) {
  21. Gson gson = new Gson();
  22. redisTemplate.opsForValue().set(key, gson.toJson(user), time, TimeUnit.MINUTES);
  23. }
  24.  
  25. public void add(String key, Long time, List<User> users) {
  26. Gson gson = new Gson();
  27. redisTemplate.opsForValue().set(key, gson.toJson(users), time, TimeUnit.MINUTES);
  28. }
  29.  
  30. public User get(String key) {
  31. Gson gson = new Gson();
  32. User user = null;
  33. String json = redisTemplate.opsForValue().get(key);
  34. if(!StringUtils.isEmpty(json))
  35. user = gson.fromJson(json, User.class);
  36. return user;
  37. }
  38.  
  39. public List<User> getList(String key) {
  40. Gson gson = new Gson();
  41. List<User> ts = null;
  42. String listJson = redisTemplate.opsForValue().get(key);
  43. if(!StringUtils.isEmpty(listJson))
  44. ts = gson.fromJson(listJson, new TypeToken<List<User>>(){}.getType());
  45. return ts;
  46. }
  47.  
  48. public void delete(String key){
  49. redisTemplate.opsForValue().getOperations().delete(key);
  50. }
  51. }

二、部署并访问应用

http://localhost/druid/index.html:访问Druid监控页面

【Spring Boot&&Spring Cloud系列】提高数据库访问性能的更多相关文章

  1. Spring Boot入门(六):使用MyBatis访问MySql数据库(注解方式)

    本系列博客记录自己学习Spring Boot的历程,如帮助到你,不胜荣幸,如有错误,欢迎指正! 本篇博客我们讲解下在Spring Boot中使用MyBatis访问MySql数据库的简单用法. 1.前期 ...

  2. Java面试题(Spring Boot/Spring Cloud篇)

    Spring Boot/Spring Cloud 104.什么是 spring boot? SpringBoot是一个框架,一种全新的编程规范,他的产生简化了框架的使用,所谓简化是指简化了Spring ...

  3. Spring Boot + Spring Cloud 实现权限管理系统 后端篇(七):集成 Druid 数据源

    数据库连接池负责分配.管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个:释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏 ...

  4. spring Boot+spring Cloud实现微服务详细教程第二篇

    上一篇文章已经说明了一下,关于spring boot创建maven项目的简单步骤,相信很多熟悉Maven+Eclipse作为开发常用工具的朋友们都一目了然,这篇文章主要讲解一下,构建spring bo ...

  5. Spring Boot 2.0系列文章(五):Spring Boot 2.0 项目源码结构预览

    关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/04/15/springboot2_code/ 项目结构 结构分析: Spring-boot-pr ...

  6. Spring Boot 2.x 系列教程:WebFlux REST API 全局异常处理 Error Handling

    摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 本文内容 为什么要全局异常处理? WebFlux REST 全 ...

  7. 【spring boot】12.spring boot对多种不同类型数据库,多数据源配置使用

    2天时间,终于把spring boot下配置连接多种不同类型数据库,配置多数据源实现! ======================================================== ...

  8. 新书上线:《Spring Boot+Spring Cloud+Vue+Element项目实战:手把手教你开发权限管理系统》,欢迎大家买回去垫椅子垫桌脚

    新书上线 大家好,笔者的新书<Spring Boot+Spring Cloud+Vue+Element项目实战:手把手教你开发权限管理系统>已上线,此书内容充实.材质优良,乃家中必备垫桌脚 ...

  9. Spring Mvc和Mybatis的多数据库访问配置过程

    Spring Mvc 加Mybatis的多数据库访问源配置访问过程如下: 在applicationContext.xml进行配置 <?xml version="1.0" en ...

随机推荐

  1. unity--------prefab嵌套prefab

    最近造了个轮子可以批量替换prefab里的prefab,欢迎大家测试-  https://bitbucket.org/xuanyusong/prefab-replace 最近在做UI部分中遇到了这样的 ...

  2. nodejs基础 -- web模块

    什么是 Web 服务器? Web服务器一般指网站服务器,是指驻留于因特网上某种类型计算机的程序,Web服务器的基本功能就是提供Web信息浏览服务.它只需支持HTTP协议.HTML文档格式及URL,与客 ...

  3. nginx+Uwsgi+Django总结与分析

    配置与调试nginx与uwsgi 參考: 1.uWSGI其三:uWSGI搭配Nginx使用 2.学习VirtualEnv和Nginx+uwsgi用于django项目部署 3.部署备忘 4.nginx+ ...

  4. 随手记录一下 Vue 下来框搜索 select2 封装成vue

    引入布局文件 <link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css& ...

  5. resharper安装后,F12不能转到定义,也不是反编译,而是转到对象浏览器(object browser)

    问: resharper安装后,一不小心点错了(选择了object browser)以上配置在哪里设置?转到定义用习惯了. 回答 :打开Resharper,选择Options,然后选择Tools中的E ...

  6. MySQL5.6主从复制搭建基于日志(binlog)

    什么是MySQL主从复制 简单来说,就是保证主SQL(Master)和从SQL(Slave)的数据是一致性的,向Master插入数据后,Slave会自动从Master把修改的数据同步过来(有一定的延迟 ...

  7. 使用ssh-keygen和ssh-copy-id三步实现SSH无密码登录

    ssh-keygen  产生公钥与私钥对. ssh-copy-id 将本机的公钥复制到远程机器的authorized_keys文件中,ssh-copy-id也能让你有到远程机器的home, ~./ss ...

  8. MySQL的varchar长度问题

    From: http://blog.csdn.net/longyulu/article/details/7863737 http://dinglin.iteye.com/blog/914276 htt ...

  9. ASP利用xhEditor编辑器实现图片上传的功能。

    本人这几天在做一个软件,无意中用到xhEditor在线编辑器,这个编辑器虽然看着比较简单,但功能非常强大,大家可以去官网上查看,废话不说了. 这篇文件主要是实现在ASP环境中利用xhEditor编辑器 ...

  10. 基金、社保和QFII等机构的重仓股排名评测

    来源:基金前20大重仓股持仓股排名 基金前15大重仓股持仓股排名 基金重仓前15大个股,相较于同期沪深300的平均收益,近1月:-1.05%,近3月:-0.49%,近6月:1.45%,近1年:3.92 ...