【Spring Boot&&Spring Cloud系列】提高数据库访问性能
前言
使用关系型数据库的应用系统的性能瓶颈最终还是数据库。随着业务的迅速增长,数据量会不断增大,会逐渐暴露关系型数据库的弱点,性能会大幅度的降低
项目地址: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依赖
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.29</version>
</dependency>
2、使用XML配置
使用Spring开发框架时,XML配置是经常使用的一种配置方法,其中数据源配置就是使用XML配置的一种。使用Spring Boot框架也能使用XML配置,只要在程序入口使用一个注解即@ImportResource({"classpath:spring-datasource.xml"}),即可导入XML配置,但是Spring Boot更推荐使用application.properties或application.yum文件来进行配置
server.port=80
server.tomcat.uri-encoding=utf-8 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/dev?characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456
#初始化大小
spring.datasource.initial-size=5
#最小
spring.datasource.min-idle=5
#最大
spring.datasource.max-active=20
#配置获取连接等待超时的时间
spring.datasource.max-wait=60000
#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.time-between-eviction-runs-millis=60000
#配置一个连接在池中最小生存的时间,单位是毫秒
spring.datasource.min-evictable-idle-time-millis=300000
spring.datasource.validation-query=SELECT 1 FROM DUAL
spring.datasource.test-while-idle=true
spring.datasource.test-on-borrow=false
spring.datasource.test-on-return=false
#打开PSCache,并且指定每个连接上的PSCache的大小
spring.datasource.pool-prepared-statements=true
spring.datasource.max-pool-prepared-statement-per-connection-size=20
#配置监控统计拦截的filters,去掉后监控界面sql无法统计 wall用于防火墙
spring.datasource.filters=stat,wall,log4j
spring.datasource.connection-properties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 spring.jpa.database=mysql
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect spring.redis.host=localhost
spring.redis.port=6379
spring.redis.pool.max-idle=8
spring.redis.pool.min-idle=0
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1
3、开启监控功能
开启Druid的监控功能可以在应用运行的过程中,通过监控提供的多维度数据来分析使用数据库的运行情况。从而调整程序设计,以优化数据库的访问性能。
设置访问连接地址为“/druid/*”,设定访问数据库的白名单和黑名单,即通过访问者的IP来控制访问员,增加了数据库的安全设置,还配置了用于登陆的用户名和密码。
package com.slp.dbexpand; import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; /**
* Created by sangliping on 2017/9/1.
*/
@Configuration
public class DruidConfiguration {
@Bean
public ServletRegistrationBean statViewServlet(){
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
//白名单
servletRegistrationBean.addInitParameter("allow","127.0.01");
//IP黑名单(共同存在时,deny优先于allow)
servletRegistrationBean.addInitParameter("deny","192.168.1.100");
//登陆查看新的是账户密码
servletRegistrationBean.addInitParameter("loginUsername","druid");
servletRegistrationBean.addInitParameter("loginPassword","123456");
//是否能够重置数据
servletRegistrationBean.addInitParameter("resetEnable","false");
return servletRegistrationBean;
} @Bean
public FilterRegistrationBean statFilter(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
//添加过滤规则
filterRegistrationBean.addUrlPatterns("/*");
//添加不需要忽略的格式信息
filterRegistrationBean.addInitParameter("exclusions","*.js.*.gif,*.png,*.css,*.ico,/druid/*");
return filterRegistrationBean;
}
}
4、扩展JPA实现
4.1首先创建一个接口,继承与JpaRepository,并将接口标记为@NoRepositoryBean以防被当做一般的Repository调用,该接口不仅扩展了原来的findOne、findAll、count等方法而且增加了deleteById、getEntityClass、nativeQuery4Map等方法,其中nativeQuery4Map用于执行原生的复杂的SQL查询语句。
package com.slp.dbexpand.jpa.repository; import com.slp.dbexpand.jpa.parameter.Operator;
import com.slp.dbexpand.jpa.parameter.Predicate;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean; import java.io.Serializable;
import java.util.List;
import java.util.Map;
/**
* Created by sangliping on 2017/9/1.
*/
@NoRepositoryBean
public interface ExpandJpaRepository <T, ID extends Serializable> extends JpaRepository<T,ID> {
T findOne(String condition, Object... objects); List<T> findAll(String condition, Object... objects); List<T> findAll(Iterable<Predicate> predicates, Operator operator); List<T> findAll(Iterable<Predicate> predicates, Operator operator, Sort sort); Page<T> findAll(Iterable<Predicate> predicates, Operator operator, Pageable pageable); long count(Iterable<Predicate> predicates, Operator operator); List<T> findAll(String condition, Sort sort, Object... objects); Page<T> findAll(String condition, Pageable pageable, Object... objects); long count(String condition, Object... objects); void deleteByIds(Iterable<ID> ids); Class<T> getEntityClass(); List<Map<String,Object>> nativeQuery4Map(String sql); Page<Map> nativeQuery4Map(String sql, Pageable pageable); Object nativeQuery4Object(String sql);
}
package com.slp.dbexpand.jpa.repository; import com.slp.dbexpand.jpa.Exception.DataException;
import com.slp.dbexpand.jpa.parameter.Operator;
import com.slp.dbexpand.jpa.parameter.Predicate;
import org.hibernate.SQLQuery;
import org.hibernate.transform.Transformers;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.query.QueryUtils;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository; import javax.persistence.*;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.*; import static org.apache.commons.lang3.StringUtils.*; /**
* Created by sangliping on 2017/9/1.
*/
public class ExpandJpaRepositoryImpl<T,ID extends Serializable> extends SimpleJpaRepository<T,ID> implements ExpandJpaRepository<T,ID> { private final EntityManager entityManager;
private final JpaEntityInformation<T, ?> entityInformation; public ExpandJpaRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
super(entityInformation, entityManager);
this.entityManager = entityManager;
this.entityInformation = entityInformation;
} @Override
public T findOne(String condition, Object... values) {
if(isEmpty(condition)){
throw new NullPointerException("条件不能为空!");
}
T result = null;
try {
result = (T) createQuery(condition, values).getSingleResult();
} catch (NoResultException e) {
e.printStackTrace();
}
return result; } @Override
public List<T> findAll(Iterable<Predicate> predicates, Operator operator) {
return new JpqlQueryHolder(predicates,operator).createQuery().getResultList();
} @Override
public List<T> findAll(Iterable<Predicate> predicates, Operator operator, Sort sort) {
return new JpqlQueryHolder(predicates,operator,sort).createQuery().getResultList();
} @Override
public Page<T> findAll(Iterable<Predicate> predicates, Operator operator, Pageable pageable) {
if(pageable==null){
return new PageImpl<T>((List<T>) findAll(predicates,operator));
} Long total = count(predicates,operator); Query query = new JpqlQueryHolder(predicates,operator,pageable.getSort()).createQuery();
query.setFirstResult(pageable.getOffset());
query.setMaxResults(pageable.getPageSize()); List<T> content = total > pageable.getOffset() ? query.getResultList() : Collections.<T> emptyList(); return new PageImpl<T>(content, pageable, total);
} @Override
public List<T> findAll(String condition, Object... objects) {
return createQuery(condition, objects).getResultList();
} @Override
public List<T> findAll(String condition, Sort sort, Object... objects) {
return createQuery(condition, sort, objects).getResultList();
} @Override
public Page<T> findAll(String condition, Pageable pageable, Object... objects) { if(pageable==null){
return new PageImpl<T>((List<T>) findAll(condition,objects));
} Long total = count(condition,objects); Query query = createQuery(condition, pageable.getSort(), objects);
query.setFirstResult(pageable.getOffset());
query.setMaxResults(pageable.getPageSize()); List<T> content = total > pageable.getOffset() ? query.getResultList() : Collections.<T> emptyList(); return new PageImpl<T>(content, pageable, total);
} @Override
public Page<T> findAll(Pageable pageable) {
return this.findAll("", pageable);
} @Override
public List<T> findAll(Iterable<ID> ids) {
return this.findAll("x."+getIdName()+" in ?1",ids);
} @Override
public long count(String condition, Object... objects) {
return new JpqlQueryHolder(condition,objects).createCountQuery().getSingleResult();
} @Override
public long count(Iterable<Predicate> predicates, Operator operator) {
return new JpqlQueryHolder(predicates,operator).createCountQuery().getSingleResult();
} @Override
public void deleteByIds(Iterable<ID> ids) {
List<T> tlist = super.findAll(ids);
super.deleteInBatch(tlist);
} @Override
public Class<T> getEntityClass() {
return entityInformation.getJavaType();
} public String getIdName(){
Class<?> entityClass = getEntityClass();
do{
Field[] fields = entityClass.getDeclaredFields();
for(Field field:fields){
if(field.getAnnotation(Id.class)!=null){
return field.getName();
}
}
entityClass = entityClass.getSuperclass();
}while (entityClass != Object.class);
throw new DataException("未设置主键",DataException.noID);
} @Override
public List<Map<String, Object>> nativeQuery4Map(String sql) {
Query nativeQuery = entityManager.createNativeQuery(sql);
nativeQuery.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
return nativeQuery.getResultList();
} @Override
public Page<Map> nativeQuery4Map(String sql, Pageable pageable) {
Query nativeQuery = entityManager.createNativeQuery(sql);
nativeQuery.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
nativeQuery.setFirstResult(pageable.getOffset());
nativeQuery.setMaxResults(pageable.getPageSize()); Query countNativeQuery = entityManager.createNativeQuery("select count(*) from ("+sql+") a");
long total = Long.valueOf(String.valueOf(countNativeQuery.getSingleResult())); return new PageImpl<Map>(nativeQuery.getResultList(),pageable,total);
} @Override
public Object nativeQuery4Object(String sql) {
Query nativeQuery = entityManager.createNativeQuery(sql); List results=nativeQuery.getResultList();
if(results==null || results.size()==0){
return null;
}
try{
if(results.size()>1){
throw new RuntimeException("结果应当只有一个,但是发现了"+results.size()+"个。");
}
return results.get(0);
}catch (NoResultException e){
return null ;
} } private TypedQuery createCountQuery(String condition, Object[] objects){ JpqlQueryHolder queryHolder = new JpqlQueryHolder(condition,objects); return queryHolder.createCountQuery();
} /**
* 声明entityClass的查询
*/
private Query createQuery(String condition, Sort sort, Object[] objects) { JpqlQueryHolder queryHolder = new JpqlQueryHolder(condition,sort,objects); return queryHolder.createQuery();
} /**
* 声明entityClass的查询
*/
private Query createQuery(String condition, Object[] objects) {
return createQuery(condition, null, objects);
} private class JpqlQueryHolder { //别名
private final String ALIAS = "x"; //QUERY ALL
private final String FIND_ALL_QUERY_STRING = "from %s "+ALIAS; //传入的condition 排除列表
private final String[] IGNORE_CONSTAINS_CHARSEQUENCE = {"where","WHERE","from","FROM"}; private String condition = null;
private Sort sort;
private Object[] objects;
private Iterable<Predicate> predicates;
private Operator operator = Operator.AND; private JpqlQueryHolder(Iterable<Predicate> predicates, Operator operator, Sort sort) {
this.predicates = predicates;
this.operator = operator;
this.sort = sort;
} private JpqlQueryHolder(Iterable<Predicate> predicates , Operator operator ) {
this.operator = operator;
this.predicates = predicates;
} private JpqlQueryHolder(String condition, Sort sort, Object[] objects) {
this(condition,objects);
this.sort = sort;
} private JpqlQueryHolder(String condition, Object[] objects) { if(startsWithAny(condition,IGNORE_CONSTAINS_CHARSEQUENCE)){
throw new DataException("查询条件中只能包含WHERE条件表达式!",DataException.noPermission);
}
this.condition = trimToNull(condition);
this.objects = objects;
} private Query createQuery(){
StringBuilder sb = new StringBuilder();
// select x from table
sb.append(QueryUtils.getQueryString(FIND_ALL_QUERY_STRING, entityInformation.getEntityName()))
//where
.append(applyCondition()); Query query = entityManager.createQuery(QueryUtils.applySorting(sb.toString(), sort, ALIAS));
applyQueryParameter(query);
return query;
} private TypedQuery<Long> createCountQuery(){
String ql = String.format(QueryUtils.COUNT_QUERY_STRING, ALIAS, "%s");
ql = QueryUtils.getQueryString(ql, entityInformation.getEntityName());
ql += applyCondition(); TypedQuery<Long> query = entityManager.createQuery(ql,Long.class);
applyQueryParameter(query);
return query;
} private List<String> map2Conditions(){
if(predicates==null||!predicates.iterator().hasNext()){
return new ArrayList<String>();
}
List<String> conditions = new ArrayList<String>(); Iterator<Predicate> iterator = predicates.iterator();
int index = 0 ;
while (iterator.hasNext()){
Predicate predicate = iterator.next();
if(predicate.getKey()==null){
continue;
}
conditions.add(predicate.toCondition(String.valueOf(index)));
index++ ;
}
return conditions;
} private String applyCondition(){
List<String> conditions = map2Conditions();
if(condition!=null) {
conditions.add(condition);
}
condition = join(conditions, " " + operator.name() + " ");
return isEmpty(condition)?"":" where "+condition;
} private void applyQueryParameter(Query query){
if(objects!=null){
int i = 0;
for(Object value:objects){
i++;
query.setParameter(i,value);
}
}
if(predicates!=null&&predicates.iterator().hasNext()){
int index = 0 ;
Iterator<Predicate> iterator = predicates.iterator();
while (iterator.hasNext()){
Predicate predicate = iterator.next();
predicate.setParameter(query,String.valueOf(index));
index++ ;
}
}
}
} }
4.2、装配自定义的扩展接口
自定义的接口必须在程序启动的时候装配,才能正常使用。首先创建一个ExpandJpaRepositoryFactoryBean继承于JpaRepositoryFactoryBean,用于加载自定义的扩展接口,其中getTargetRepository返回自定义的接口实现ExpandJpaRepositoryImpl:
package com.slp.dbexpand.jpa.repository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport; import javax.persistence.EntityManager;
import java.io.Serializable; /**
* Created by sangliping on 2017/9/1.
*/
public class ExpandJpaRepositoryBean<R extends JpaRepository<T, ID>, T, ID extends Serializable>extends JpaRepositoryFactoryBean<R, T, ID> {
protected RepositoryFactorySupport createRepositoryFactory(
EntityManager entityManager) {
return new ExpandJpaRepositoryFactory<T, ID>(entityManager);
} private static class ExpandJpaRepositoryFactory<T, ID extends Serializable>
extends JpaRepositoryFactory { private final EntityManager entityManager; public ExpandJpaRepositoryFactory(EntityManager entityManager) { super(entityManager);
this.entityManager = entityManager;
} protected Object getTargetRepository(RepositoryMetadata metadata) {
JpaEntityInformation<T, Serializable> entityInformation = (JpaEntityInformation<T, Serializable>) getEntityInformation(metadata.getDomainType());
return new ExpandJpaRepositoryImpl<T, ID>(entityInformation, entityManager);
} protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return ExpandJpaRepositoryImpl.class;
}
}
}
4.3在jpa配置类中通过@EnableJpaRepository加载定义的装配类ExpandJpaRepositoryFactoryBean
package com.slp.dbexpand; import com.slp.dbexpand.jpa.repository.ExpandJpaRepositoryBean;
import org.springframework.boot.orm.jpa.EntityScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement; /**
* Created by sangliping on 2017/9/1.
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@EnableTransactionManagement(proxyTargetClass = false)
@EnableJpaRepositories(basePackages = "com.slp.repository",repositoryFactoryBeanClass = ExpandJpaRepositoryBean.class)
@EntityScan(basePackages = "com.slp.entity")
public class JpaConfiguration {
@Bean
PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor(){
return new PersistenceExceptionTranslationPostProcessor();
}
}
4.3、使用Redis做缓存
在数据库使用中,数据查询是最大的性能开销。如果能借助Redis作为辅助缓存,将可以极大的提高数据库的访问性能。使用Redis做缓存,一方面可以调用,另一方面可以使用注解的方式调用。
值得注意的是,Redis是一个具有持久化功能的数据库系统,若使用默认配置,存取的数据就会永久的保存在磁盘中。如果只是使用Redis做缓存的话可以设定Redis保存数据的期限来实现,这样,过期的数据会自动清除。
1)使用spring cache注解
package com.slp.dbexpand.jpa;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Created by sangliping on 2017/9/1.
*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport{
@Bean
public KeyGenerator simpleKey(){
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName()+":");
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
} @Bean
public KeyGenerator objectId(){
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params){
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName()+":");
try {
sb.append(params[0].getClass().getMethod("getId", null).invoke(params[0], null).toString());
}catch (NoSuchMethodException no){
no.printStackTrace();
}catch(IllegalAccessException il){
il.printStackTrace();
}catch(InvocationTargetException iv){
iv.printStackTrace();
}
return sb.toString();
}
};
} @Bean
public CacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {
RedisCacheManager manager = new RedisCacheManager(redisTemplate);
manager.setDefaultExpiration(43200);//12小时
return manager;
} @Bean
public RedisTemplate<String, String> redisTemplate(
RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
} }
2)使用RedisTemplate
package com.slp.redis;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.slp.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils; import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* Created by sangliping on 2017/9/1.
*/
@Repository
public class UserRedis {
@Autowired
private RedisTemplate<String, String> redisTemplate; public void add(String key, Long time, User user) {
Gson gson = new Gson();
redisTemplate.opsForValue().set(key, gson.toJson(user), time, TimeUnit.MINUTES);
} public void add(String key, Long time, List<User> users) {
Gson gson = new Gson();
redisTemplate.opsForValue().set(key, gson.toJson(users), time, TimeUnit.MINUTES);
} public User get(String key) {
Gson gson = new Gson();
User user = null;
String json = redisTemplate.opsForValue().get(key);
if(!StringUtils.isEmpty(json))
user = gson.fromJson(json, User.class);
return user;
} public List<User> getList(String key) {
Gson gson = new Gson();
List<User> ts = null;
String listJson = redisTemplate.opsForValue().get(key);
if(!StringUtils.isEmpty(listJson))
ts = gson.fromJson(listJson, new TypeToken<List<User>>(){}.getType());
return ts;
} public void delete(String key){
redisTemplate.opsForValue().getOperations().delete(key);
}
}
二、部署并访问应用
http://localhost/druid/index.html:访问Druid监控页面
【Spring Boot&&Spring Cloud系列】提高数据库访问性能的更多相关文章
- Spring Boot入门(六):使用MyBatis访问MySql数据库(注解方式)
本系列博客记录自己学习Spring Boot的历程,如帮助到你,不胜荣幸,如有错误,欢迎指正! 本篇博客我们讲解下在Spring Boot中使用MyBatis访问MySql数据库的简单用法. 1.前期 ...
- Java面试题(Spring Boot/Spring Cloud篇)
Spring Boot/Spring Cloud 104.什么是 spring boot? SpringBoot是一个框架,一种全新的编程规范,他的产生简化了框架的使用,所谓简化是指简化了Spring ...
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(七):集成 Druid 数据源
数据库连接池负责分配.管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个:释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏 ...
- spring Boot+spring Cloud实现微服务详细教程第二篇
上一篇文章已经说明了一下,关于spring boot创建maven项目的简单步骤,相信很多熟悉Maven+Eclipse作为开发常用工具的朋友们都一目了然,这篇文章主要讲解一下,构建spring bo ...
- Spring Boot 2.0系列文章(五):Spring Boot 2.0 项目源码结构预览
关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/04/15/springboot2_code/ 项目结构 结构分析: Spring-boot-pr ...
- Spring Boot 2.x 系列教程:WebFlux REST API 全局异常处理 Error Handling
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 本文内容 为什么要全局异常处理? WebFlux REST 全 ...
- 【spring boot】12.spring boot对多种不同类型数据库,多数据源配置使用
2天时间,终于把spring boot下配置连接多种不同类型数据库,配置多数据源实现! ======================================================== ...
- 新书上线:《Spring Boot+Spring Cloud+Vue+Element项目实战:手把手教你开发权限管理系统》,欢迎大家买回去垫椅子垫桌脚
新书上线 大家好,笔者的新书<Spring Boot+Spring Cloud+Vue+Element项目实战:手把手教你开发权限管理系统>已上线,此书内容充实.材质优良,乃家中必备垫桌脚 ...
- Spring Mvc和Mybatis的多数据库访问配置过程
Spring Mvc 加Mybatis的多数据库访问源配置访问过程如下: 在applicationContext.xml进行配置 <?xml version="1.0" en ...
随机推荐
- tp5的学习
1.安装,官网下载 2.访问配置:http://localhost/App/public/ 3.入口文件,项目目录/public // 定义应用目录 define('APP_PATH', __DIR_ ...
- idea出现插件突然失灵解决方案
File -> Settings -> Plgins 把失效的插件重新去掉打钩并重新打钩即可
- 复制js的“准”正确用法
function kobe(id) { var targetText = document.getElementById(id); try ...
- Java、C#双语版HttpHelper类(解决网页抓取乱码问题)
在做一些需要抓取网页的项目时,经常性的遇到乱码问题.最省事的做法是去需要抓取的网站看看具体是什么编码,然后采用正确的编码进行解码就OK了,不过总是一个个页面亲自去判断也不是个事儿,尤其是你需要大量抓取 ...
- Blender 建模
1.多图层切换 Blender也有图层的概念,我们在一个图层上建立了一个模型,可以在另外一个图层新建一个独立的模型.界面底部包含了Layer切换按钮.如下图所示: 当前我们正在操作第一个图层,如果想在 ...
- Application runtime path "/opt/lampp/htdocs/yii/test/protected/runtime" is not valid. 错误
原因:把windows版的Yii框架写的程序中的拷到Linux去,assets和runtime目录对Group和其他的权限不够.解决方案:点击这2个文件的属性,属性框全选好了,权限777了. cd p ...
- 一个基于jquery的智能提示控件intellSeach.js
一.需求 我们经常会遇到[站内搜索]的需求,为了提高用户体验,我们希望能做到像百度那样的即时智能提示.例如:某公司人事管理系统,想搜索李XX,只要输入“李”,系统自然会提示一些姓李的员工,这样方便用户 ...
- 抓包工具Wireshark
https://baike.baidu.com/item/Wireshark/10876564?fr=aladdin
- Mac OS 电信3G上网设置
打开客户端后(安装客户端mobile partner需要先安装jdk),在“系统偏好设置”里选择“网络”,网络左侧添加“huaweimobile-modem”,“电话号码”填写电信卡号,“账户名称”和 ...
- 恶劣条件下的apache配置(Linux)
(本文出自yangjj ^_^) 前提:1.没联网,yum挂.2.至少要有GCC,要不玩个屁. 3.你有充足的咖啡并且有几个小时时间不想打dota. 4.你要做集群. 以上条件不满足其一,看到这里 ...