springboot-数据库

数据库

[toc]

MySQL

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

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

    <!--jpa-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    
    <!--mysql-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
    </dependency>
    

    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<Person, Integer> {
    }
    
  • 单表简单查询

    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<Person> findPerson() {
            return personRespository.findAll();
        }
    }
    
  • 单表根据年龄查询

    PersonRespository.java

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

    public interface PersonRespository extends JpaRepository<Person, Integer> {
        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-->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
</dependency>
<!--gson-->
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.2.4</version>
</dependency>

RedisTemplate.java Redis 配置

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

    @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;
    }
}

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<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);
    }
}

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<Role> 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<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;
        }
    
        /**
         * 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<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);
        }
    }
    

    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 依赖

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.0.9</version>
</dependency>
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);

    }
}



最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容