springboot-数据库

数据库

[toc]

MySQL

  • 准备工作,加入数据库的配置和依赖

    为了使用 jpamysql,在 pom.xml文件中增加依赖。

    
    
      org.springframework.boot
      spring-boot-starter-data-jpa
    
    
    
    
      mysql
      mysql-connector-java
    
    

    application.yml 配置 mysql 连接信息

    spring:
      datasource:
        url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8
        username: root
        password: root
    
    # jpa
      jpa:
        database: MYSQL
        show-sql: true
    # Hibernate ddl auto (validate|create|create-drop|update)
        hibernate:
          ddl-auto: update
          naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy
        properties:
          hibernate:
            dialect: org.hibernate.dialect.MySQL5Dialect
    

    Person.java

    @Entity
    public class Person {
    
        @Id
        @GeneratedValue
        private Integer id;
        private String name;
        private Integer age;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    }
    

    创建接口继承JpaRepository,泛型使用的是

    public interface PersonRespository extends JpaRepository {
    }
    
  • 单表简单查询

    HelloController.java

    @RestController
    public class HelloController {
    
        @Autowired
        private PersonRespository personRespository;
    
        @PostMapping(value = "/addPerson")
        public Person addPerson(@RequestParam(value = "name") String name, @RequestParam(value = "age") Integer age) {
            Person person = new Person();
            person.setName(name);
            person.setAge(age);
            return personRespository.save(person);
        }
        
            @DeleteMapping(value = "/delPerson/{id}")
        public void delPerson(@PathVariable(value = "id") Integer id) {
            personRespository.delete(id);
        }
    
        @PutMapping(value = "/updatePerson")
        public Person updatePerson(@RequestParam(value = "id") Integer id, @RequestParam(value = "name") String name, @RequestParam(value = "age") Integer age) {
            Person person = new Person();
            person.setId(id);
            person.setName(name);
            person.setAge(age);
            return personRespository.save(person);
        }
    
        @GetMapping(value = "/findPerson/{id}")
        public Person findPerson(@PathVariable(value = "id") Integer id) {
            return personRespository.findOne(id);
        }
    
        @GetMapping(value = "/findPersons")
        public List findPerson() {
            return personRespository.findAll();
        }
    }
    
  • 单表根据年龄查询

    PersonRespository.java

    增加一个根据年龄查询的抽象方法

    public interface PersonRespository extends JpaRepository {
        Person findByAge(Integer age);
    }
    

    HelloController.java

    @RestController
    public class HelloController {
    
        @Autowired
        private PersonRespository personRespository;
    
        @GetMapping(value = "/findPersonByAge/{age}")
        public Person findPersonByAge(@PathVariable(value = "age") Integer age) {
            return personRespository.findByAge(age);
        }
    }
    



集成 Redis

pom.xml



    redis.clients
    jedis


    org.springframework.data
    spring-data-redis



    com.google.code.gson
    gson
    2.2.4

RedisTemplate.java Redis 配置

/**
 * RedisTemplate 初始化
 */
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate 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;
    }
}

application.yml 配置 redis 连接信息

spring:

# redis 配置,没有密码的话,可以不写 password 或者 password 值不填写
  redis:
    host: 192.168.18.130
    port: 6379
    pool:
      max-idle: 8
      min-idle: 0
      max-active: 8
      max-wait: -1

UserRedis.java 用户模块的 redis 增删改查

@Repository
public class UserRedis {

    @Autowired
    private RedisTemplate 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 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 getList(String key) {
        Gson gson = new Gson();
        List ts = null;
        String listJson = redisTemplate.opsForValue().get(key);
        if (!StringUtils.isEmpty(listJson))
            ts = gson.fromJson(listJson, new TypeToken>() {
            }.getType());
        return ts;
    }

    public void delete(String key) {
        redisTemplate.opsForValue().getOperations().delete(key);
    }
}

RedisController.java 接口类测试

@RestController
@RequestMapping(value = "/springboot")
public class RedisController {


    private static Logger logger = LoggerFactory.getLogger(RedisController.class);

    @Autowired
    UserRedis userRedis;

    @Autowired
    RoleService roleService;

    @RequestMapping(value = "/getRedis")
    public void getRedis() {
        Department deparment = new Department();
        deparment.setName("开发部");

        Role role = new Role();
        role.setName("admin");

        User user = new User();
        user.setName("user");
        user.setCreatedate(new Date());
        user.setDeparment(deparment);

        List roles = new ArrayList<>();
        roles.add(role);

        user.setRoles(roles);

        userRedis.delete(this.getClass().getName() + ":userByname:" + user.getName());
        userRedis.add(this.getClass().getName() + ":userByname:" + user.getName(), 10L, user);

        User userRes = userRedis.get(this.getClass().getName() + ":userByname:user");
        Assert.notNull(userRes);
        logger.info("======userRes====== name:{}, deparment:{}, role:{}",
                userRes.getName(), userRes.getDeparment().getName(), userRes.getRoles().get(0).getName());
    }

    @RequestMapping(value = "/springcache_redis_create")
    public Role springcache_redis_create() {
        Role role = new Role();
        role.setName("jack");
        return roleService.create(role);
    }

    @RequestMapping(value = "/springcache_redis_find/{id}", method = RequestMethod.GET)
    public Role springcache_redis_find(@PathVariable(value = "id") Long id) {
        return roleService.findById(id);
    }

    @RequestMapping(value = "/springcache_redis_update/{id}", method = RequestMethod.GET)
    public Role springcache_redis_update(@PathVariable(value = "id") Long id) {
        Role role = roleService.findById(id);
        role.setName("rose");
        return roleService.update(role);
    }

    @RequestMapping(value = "/springcache_redis_delete/{id}", method = RequestMethod.GET)
    public void springcache_redis_delete(@PathVariable(value = "id") Long id) {
        roleService.delete(id);
    }
}



Redis 缓存优化

Spring Cache 注解

结构简单的对象,即没有包含其他对象的实体,可以用 spring cache 的方式使用 redis 缓存,前提是打开 spring cache

  • Spring Cache 配置

    /**
     * 结构简单的对象,既没有包含其他对象的实体,可以用 spring cache 的方式使用 redis 缓存
     * 前提是打开 spring cache
     */
    @Configuration
    @EnableCaching
    public class RedisConfig extends CachingConfigurerSupport {
    
        @Bean
        public RedisTemplate 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;
        }
    
        /**
         * Spring Cache 配置
         * @param redisTemplate
         * @return
         */
        @Bean
        public CacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {
            RedisCacheManager manager = new RedisCacheManager(redisTemplate);
            manager.setDefaultExpiration(43200);//12小时
            return manager;
        }
    
        /**
         * simpleKey 根据 类名+参数 id 作为唯一标识
         * @Cacheable 存取缓存
         * @CachePut 更新缓存
         * @CacheEvict 删除缓存
         * 注解中的 value 参数是一个 key 的前缀,
         * 并由 keyGenerator 按照一定的规则生成一个唯一的标识
         */
        @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();
                }
            };
        }
    
        /**
         * objectId 根据 类名+参数 id 作为唯一标识
         * @Cacheable 存取缓存
         * @CachePut 更新缓存
         * @CacheEvict 删除缓存
         * 注解中的 value 参数是一个 key 的前缀,
         * 并由 keyGenerator 按照一定的规则生成一个唯一的标识
         */
        @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();
                }
            };
        }
    }
    

    RoleService.java 使用 Spring Cache 注解来用 redis 操作。

    @Service
    public class RoleService {
        @Autowired
        private RoleRepository roleRepository;
    
        /**
         * @Cacheable(value = "mysql:findById:role", keyGenerator = "simpleKey")
         * value = "mysql:findById:role" 是一个key 的前缀,并由 keyGenerator 按照一定的规则生成一个唯一的标识
         * @Cacheable 存取缓存
         * @CachePut 更新缓存
         * @CacheEvict 删除缓存
         */
    
        @Cacheable(value = "mysql:findById:role", keyGenerator = "simpleKey")
        public Role findById(Long id) {
            return roleRepository.findOne(id);
        }
    
        @CachePut(value = "mysql:findById:role", keyGenerator = "objectId")
        public Role create(Role role) {
            return roleRepository.save(role);
        }
    
        @CachePut(value = "mysql:findById:role", keyGenerator = "objectId")
        public Role update(Role role) {
            return roleRepository.save(role);
        }
    
        @CacheEvict(value = "mysql:findById:role", keyGenerator = "simpleKey")
        public void delete(Long id) {
            roleRepository.delete(id);
        }
    }
    
  • 使用 Redis Template,配置可以参考第2章的RedisConfig.java

    @Repository
    public class UserRedis {
    
        @Autowired
        private RedisTemplate 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 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 getList(String key) {
            Gson gson = new Gson();
            List ts = null;
            String listJson = redisTemplate.opsForValue().get(key);
            if (!StringUtils.isEmpty(listJson))
                ts = gson.fromJson(listJson, new TypeToken>() {
                }.getType());
            return ts;
        }
    
        public void delete(String key) {
            redisTemplate.opsForValue().getOperations().delete(key);
        }
    }
    

    UserService.java 存储和查询策略,先查询 redis,不存在再查询数据库同时添加到 redis

    /**
     * 先查询 redis,不存在再查询数据库同时添加到 redis
     */
    @Service
    public class UserService {
        @Autowired
        private UserRepository userRepository;
        @Autowired
        private UserRedis userRedis;
        private static final String keyHead = "mysql:get:user:";
    
        public User findById(Long id) {
            User user = userRedis.get(keyHead + id);
            if (user == null) {
                user = userRepository.findOne(id);
                if (user != null)
                    userRedis.add(keyHead + id, 30L, user);
            }
            return user;
        }
    
        public User create(User user) {
            User newUser = userRepository.save(user);
            if (newUser != null)
                userRedis.add(keyHead + newUser.getId(), 30L, newUser);
            return newUser;
        }
    
        public User update(User user) {
            if (user != null) {
                userRedis.delete(keyHead + user.getId());
                userRedis.add(keyHead + user.getId(), 30L, user);
            }
            return userRepository.save(user);
        }
    
        public void delete(Long id) {
            userRedis.delete(keyHead + id);
            userRepository.delete(id);
        }
    
    }
    



提高数据库访问性能

Druid

pom.xml 增加 druid 依赖


  com.alibaba
  druid
  1.0.9

server:
  port: 8080
  tomcat:
    uri-encoding: utf-8
spring:
#系统默认的 DataSource
#  datasource:
#    url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8
#    username: root
#    password: root

#阿里的 DruidDataSourc
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test?characterEncoding=utf8
    username: root
    password: 12345678
    # 初始化大小,最小,最大
    initialSize: 5
    minIdle: 5
    maxActive: 20
    # 配置获取连接等待超时的时间
    maxWait: 60000
    # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
    timeBetweenEvictionRunsMillis: 60000
    # 配置一个连接在池中最小生存的时间,单位是毫秒
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    # 打开PSCache,并且指定每个连接上PSCache的大小
    poolPreparedStatements: true
    maxPoolPreparedStatementPerConnectionSize: 20
    # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
    filters: stat,wall,log4j
    # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
    # 合并多个DruidDataSource的监控数据
    #useGlobalDataSourceStat=true

  # jpa
  jpa:
    database: MYSQL
    show-sql: true
  #Hibernate ddl auto (validate|create|create-drop|update)
    hibernate:
      ddl-auto: update
      naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL5Dialect

  # redis 配置,没有密码的话,可以不写 password 或者 password 值不填写
  redis:
    host: 192.168.18.130
    port: 6379
    password:
    pool:
      max-idle: 8
      min-idle: 0
      max-active: 8
      max-wait: -1



事务管理

在方法名称上增加@Transactional,该方法就有事务管理了。

@Service
public class PersonService {

    @Autowired
    private PersonRespository personRespository;

    @Transactional
    public void insertTwo() {
        Person person = new Person();
        person.setName("jack");
        person.setAge(40);
        personRespository.save(person);

        Person person1 = new Person();
        person1.setName("rose");
        person1.setAge(30000);
        int a = 1 / 0;
        personRespository.save(person1);

    }
}



你可能感兴趣的:(springboot-数据库)