暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

整合MySQL,JDBCTemplate

别人家Java 2021-07-16
242

点击上方蓝色别人家Java,选择“关注


从今天起我们将开始学习SpringBoot数据篇,本篇将讲解整合MySQL、 整合JDBCTemplate、 整合Durid方面的内容。


整合MySQL


在整合MySQL之前,我们首先要清楚两个问题:
  • 什么是JDBC?

JDBC(JavaDataBaseConnectivity),用于执行SQL语句的JavaApi。我们本文主要讲的是Spring JDBC,它是对于JDBC的封装,让我们使用JDBC时更加简单方便快捷。

  • 什么是持久层?

持久层(Persistence Layer),对数据进行持久化操作(例:将数据保存到数据库的操作),把数据保存起来或者把持久状态的数据查询出来。(有关于以上操作的代码都是持久层代码)


Spring JDBC集成


首先我们在pom.xml文件中导入maven依赖:

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

之后我们在application.yml中添加数据源配置:

datasource:
    driver-class-namecom.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/Family?serverTimezone=GMT%2b8&characterEncoding=utf-8
    username: root
    password: 123456

在数据库中创建pets表:

/*
 Navicat Premium Data Transfer

 Source Server         : javafamily
 Source Server Type    : MySQL
 Source Server Version : 50729
 Source Host           : localhost:3306
 Source Schema         : Family

 Target Server Type    : MySQL
 Target Server Version : 50729
 File Encoding         : 65001
*/


SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for pets
-- ----------------------------
DROP TABLE IF EXISTS `pets`;
CREATE TABLE `pets` (
  `id` int(11NOT NULL AUTO_INCREMENT,
  `name` varchar(32NOT NULL,
  `varieties` varchar(32NOT NULL,
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='宠物';

SET FOREIGN_KEY_CHECKS = 1;

我们在javafamily.familydemo文件下创建文件夹dao并在其中创建PetsDAO.class:

package com.javafamily.familydemo.dao;

import com.javafamily.familydemo.model.Pets;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import java.util.List;

// 表示当前类是持久层依赖注入的对象
@Repository
public class PetsDAO {

    @Resource
    // 进行JDBC操作的模版类(由Spring JDBC提供)
    private JdbcTemplate jdbcTemplate;

    // 增加一只宠物的信息
    public void save(Pets pets) {
        // jdbcTemplate.update适合于insert 、update和delete操作,不适合查询操作。
        jdbcTemplate.update("INSERT INTO pets(name,varieties,create_time) values(?, ?, ?)",
                pets.getName(),
                pets.getVarieties(),
                pets.getCreateTime());
    }

    // 删除一只宠物的信息
    public void deleteById(Long id) {
        jdbcTemplate.update("DELETE FROM pets WHERE id = ?", id);
    }

    // 修改一只宠物信息
    public void updateById(Pets pets) {
        jdbcTemplate.update("UPDATE pets SET name = ?,varieties = ?,create_time = ? WHERE id = ?",
                pets.getName(),
                pets.getVarieties(),
                pets.getCreateTime(),
                pets.getId());
    }

    // 查找宠物信息,queryForObject:用于查询单条记录返回结果
    public Pets searchById(Long id) {
        return (Pets) jdbcTemplate.queryForObject("SELECT * FROM pets WHERE id=?",
                new Object[]{id}, new BeanPropertyRowMapper<>(Pets.class));
    }

    // 查询宠物信息,query:用于查询结果列表
    public List<Pets> findAll() {
        return (List<Pets>) jdbcTemplate.query("SELECT * FROM pets "new BeanPropertyRowMapper<>(Pets.class));
    }
}

在编写完Dao层的代码后,我们要思考一个问题,为什么服务端后端要采用分层开发?(controller:参数的接收和相应结果的返回。service:业务处理。repository:数据持久化以及查询相关的操作)


在比较简单的开发中,controller层是可以直接调用持久层(dao)的。但是这种方法不推荐使用,因为我们需要在service层控制事务。所以还是使用正常的调用顺序(controller->service->dao),进行分层开发。


所以下面我们来编写service层代码,我们对之前创建好的PetsService进行改造:

package com.javafamily.familydemo.service;

import com.javafamily.familydemo.model.Pets;

import java.util.List;

public interface PetsService {

    void savePets(Pets pets);

    void deletePets(long id);

    void updatePets(Pets pets);

    Pets getPets(Long id);

    List<Pets> getAll();
}

再修改一下之前的PetsServiceImpl:

package com.javafamily.familydemo.service;

import com.javafamily.familydemo.dao.PetsDAO;
import com.javafamily.familydemo.model.Pets;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

@Service
public class PetsServiceImpl implements PetsService {

    @Resource
    private PetsDAO petsDAO;

    @Override
    public void savePets(Pets pets) {
        petsDAO.save(pets);
    }

    @Override
    public void deletePets(long id) {
        petsDAO.deleteById(id);
    }

    @Override
    public void updatePets(Pets pets) {
        petsDAO.updateById(pets);
    }

    @Override
    public Pets getPets(Long id) {
        return petsDAO.searchById(id);
    }

    @Override
    public List<Pets> getAll() {
        return petsDAO.findAll();
    }
}

回到PetsController中进行修改:

package com.javafamily.familydemo.controller;

import com.javafamily.familydemo.model.Customer;
import com.javafamily.familydemo.model.Pets;
import com.javafamily.familydemo.model.Response;
import com.javafamily.familydemo.service.PetsService;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Slf4j
@RestController
public class PetsController {

    @Resource
    PetsService petsService;

    // 根据id,查询一只宠物信息
    @RequestMapping(value = "/pets/{id}", method = RequestMethod.GET)
    public Response getPets(@PathVariable("id") long id) {
        Pets pets = petsService.getPets(id);
        log.info("pets" + pets);
        return Response.success(pets);
    }

    @RequestMapping(value = "/pets", method = RequestMethod.POST)
    public Response savePets(@RequestBody Pets pets) {
        petsService.savePets(pets);
        log.info("savePets" + pets);
        return Response.success();
    }

    // 修改一只宠物信息
    @RequestMapping(value = "/pets", method = RequestMethod.PUT)
    public Response updatePets(@RequestBody Pets pets) {
        petsService.updatePets(pets);
        log.info("updatePets" + pets);

        return Response.success(pets);

    }

    // 根据id,删除一只宠物信息
    @RequestMapping(value = "/pets/{id}", method = RequestMethod.DELETE)
    public Response deletePets(@PathVariable("id") Long id) {
        petsService.deletePets(id);
        log.info("deletePets" + id);
        return Response.success();
    }

    // 查询所有宠物信息
    @RequestMapping(value = "/pets", method = RequestMethod.GET)
    public Response getPets() {
        List<Pets> pets = petsService.getAll();
        log.info("pets" + pets);
        return Response.success(pets);
    }

}

由于我们在创建数据库后没有在里面添加数据,所以在使用postman测试时data暂时显示为空。

这时向数据库中添加一条我们曾经测试过的数据:

添加完成后,我们会在数据库中看见这条数据,并且能在postman中查询出来:

我们将狗的品种改成erha:

最后删掉id为1的这条数据:

数据被成功删除。


之后我们来看@Trasactional注解:它能够进行事务管理,保证方法一旦有异常,所有的数据库操作进行回滚(比如@Trasactional注解作用在修改方法上,当出现异常修改操作将不会进行,数据库中的数据不会发生任何改变)。


以上我们介绍的是单一数据源的配置与实现,随着数据的增多,我们会逐渐使用数据分库存储的方案,那么在持久层中一个服务要操作多个数据库,那么该如何实现呢?下面我们来介绍多数据源的实现。

首先在application.yml中添加一个数据源配置:

spring:
  datasource:
    family:
      driver-class-namecom.mysql.cj.jdbc.Driver
      jdbc-url: jdbc:mysql://localhost:3306/Family?serverTimezone=GMT%2b8&characterEncoding=utf-8
      username: root
      password: 123456
    family2:
      driver-class-namecom.mysql.cj.jdbc.Driver
      jdbc-url: jdbc:mysql://localhost:3306/Family2?serverTimezone=GMT%2b8&characterEncoding=utf-8
      username: root
      password: 123456

之后在config文件中创建DataSourceConfig.java:

package com.javafamily.familydemo.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;

@Configuration
public class DataSourceConfig {

    // 当一个接口有多个时候实现类的时候,如果Spring只能选一个实现进行依赖注入时,就选这个数据源(默认数据源)
    @Primary
    @Bean(name = "familyDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.family")
    public DataSource familyDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "family2DataSource")
    @ConfigurationProperties(prefix = "spring.datasource.family2")  
    public DataSource family2DataSource() {
        return DataSourceBuilder.create().build();
    }

}


JDBCTemplate实现多数据源

在完成了图-多数据源配置的前两个步骤,我们要开始实现JDBCTemplate部分!


首先将petsDAO.class进行修改:

package com.javafamily.familydemo.dao;

import com.javafamily.familydemo.model.Pets;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import java.util.List;

// 表示当前类是持久层依赖注入的对象
@Repository
public class PetsDAO {

    @Resource
    // 进行JDBC操作的模版类(由Spring JDBC提供)
    private JdbcTemplate familyJdbcTemplate;

    // 增加一只宠物的信息
    public void save(Pets pets, JdbcTemplate jdbcTemplate) {
        if (jdbcTemplate == familyJdbcTemplate){
            jdbcTemplate = familyJdbcTemplate;
        }
        // jdbcTemplate.update适合于insert 、update和delete操作,不适合查询操作。
        jdbcTemplate.update("INSERT INTO pets(name,varieties,create_time) values(?, ?, ?)",
                pets.getName(),
                pets.getVarieties(),
                pets.getCreateTime());
    }

    // 删除一只宠物的信息
    public void deleteById(Long id,JdbcTemplate jdbcTemplate) {
        jdbcTemplate.update("DELETE FROM pets WHERE id = ?", id);
    }

    // 修改一只宠物信息
    public void updateById(Pets pets, JdbcTemplate jdbcTemplate) {
        jdbcTemplate.update("UPDATE pets SET name = ?,varieties = ?,create_time = ? WHERE id = ?",
                pets.getName(),
                pets.getVarieties(),
                pets.getCreateTime(),
                pets.getId());
    }

    // 查找宠物信息,queryForObject:用于查询单条记录返回结果
    public Pets searchById(Long id,JdbcTemplate jdbcTemplate) {
        return (Pets) jdbcTemplate.queryForObject("SELECT * FROM pets WHERE id=?",
                new Object[]{id}, new BeanPropertyRowMapper<>(Pets.class));
    }

    // 查询宠物信息,query:用于查询结果列表
    public List<Pets> findAll(JdbcTemplate jdbcTemplate) {
        return (List<Pets>) jdbcTemplate.query("SELECT * FROM pets "new BeanPropertyRowMapper<>(Pets.class));
    }
}

familyJdbcTemplate使用familyDataSource数据源操作数据库Family。

family2JdbcTemplate使用family2DataSource数据源操作数据库Family2。


再对PetsServiceImpl.java进行完善:

package com.javafamily.familydemo.service;

import com.javafamily.familydemo.dao.PetsDAO;
import com.javafamily.familydemo.model.Pets;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

@Service
public class PetsServiceImpl implements PetsService {

    @Resource
    private PetsDAO petsDAO;
    @Resource
    private JdbcTemplate familyJdbcTemplate;
    @Resource
    private JdbcTemplate family2JdbcTemplate;


    @Override
    public void savePets(Pets pets) {
        petsDAO.save(petsfamilyJdbcTemplate);
        petsDAO.save(petsfamily2JdbcTemplate);
    }

    @Override
    public void deletePets(long id) {
        petsDAO.deleteById(idnull);
    }

    @Override
    public void updatePets(Pets pets) {
        petsDAO.updateById(petsnull);
    }

    @Override
    public Pets getPets(Long id) {
        return petsDAO.searchById(idnull);
    }

    @Override
    public List<Pets> getAll() {
        return petsDAO.findAll(null);
    }
}

这时我们在数据库Family2中建立一个跟数据库Family中的一样的pets表,之后在postman中添加数据:

数据库Family和Family2中都会出现这条数据:

双数据源的配置和插入动作就完成了!

点击下方阅读原文,查看上一篇

文章转载自别人家Java,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论