(六) SpringBoot起飛之路-整合JdbcTemplate-Druid-MyBatis-Redis

有興趣的朋友可以去了解一下前五篇,你的贊就是對我最大的支持,感謝大家!

(一) SpringBoot起飛之路-HelloWorld

(二) SpringBoot起飛之路-入門原理分析

(三) SpringBoot起飛之路-YAML配置小結(入門必知必會)

(四) SpringBoot起飛之路-靜態資源處理

(五) SpringBoot起飛之路-Thymeleaf模板引擎

說明:

  • SpringBoot 起飛之路 系列文章的源碼,均同步上傳到 github 了,有需要的小夥伴,隨意去 down
    • https://github.com/ideal-20/Springboot-Study-Code
  • 才疏學淺,就會點淺薄的知識,大家權當一篇工具文來看啦,不喜勿憤哈 ~

引言

前面分別介紹了一下一些入門的配置和基礎,同時引入了Thymeleaf模板引擎,而練習一些小 Demo 就要開始涉及到數據了,所以今天來講一下如何在 SpringBoot 中整合常見數據相關的一些技術:JdbcTemplate、Druid、MyBatis,重點熟悉下後兩者,用的也是比較多的

這一篇所介紹的內容,都不是新內容,不涉及太多的語法,關鍵是整合,關於這三樣介紹也就簡單提一下

最後開始之前,還有一個需要提及的

SpringBoot 中關於數據庫相關的處理,均使用 Spring Data,它是 Spring 全家桶中的一個子項目,能同時支持關係/非關係型數據庫的操作,能夠極大地簡化數據庫訪問的操作

更多內容,可以去看一下官網:

https://spring.io/projects/spring-data

(一) 整合 JdbcTemplate

雖然叫做 整合 JdbcTemplate,但本質上還是整合 JDBC ,只不過 JdbcTemplate 對原生 JDBC 進行了一些簡化

(1) 引入依賴

我們首先創建一個 Project 或者 Module,然後初始化一個 SpringBoot 項目,除了基本的 Web 以外,再左側 SQL 選項中選擇 JDBC API ,這也就是引入關於整合 JDBC 的依賴

來看一下 pom,也就是引入了 spring-boot-starter-jdbc 這個啓動器,其中一些依賴封裝好了

詳情可以參考官網文檔,我貼了兩個版本,更多版本,自己可以去翻閱一下

https://docs.spring.io/spring-boot/docs/2.3.0.RELEASE/reference/html/using-spring-boot.html#using-boot-structuring-your-code

https://docs.spring.io/spring-boot/docs/2.2.7.RELEASE/reference/html/using-spring-boot.html#using-boot-starter

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

之前的舊版本,mysql-connector-java 應該也會被引入的,如果沒有也不必擔心,後面寫數據庫相關配置的時候,我們也會引入

(2) 修改配置

接着,我們需要在配置文件中配置數據庫的一些信息,例如用戶名密碼等等,我們用 yml 配,用 properties 也是一樣的

關於 url 這個選項多說一句,我的表名 springboot_mybatis_test,但是如果不設置時區或者一些編碼,不同的版本使用中可能會出現一些錯誤(5 可以不配置時區,高版本的需要)

而在設定時區的時候,像我下面設置爲 serverTimezone=UTC,會比中國時間早8個小時,所以中國可以選擇Asia/Shanghai或者Asia/Hongkong

spring:
  datasource:
    username: root
    password: root99
    # serverTimezone=Asia/Shanghai 這樣解決時區的報錯會好一些
    url: jdbc:mysql://localhost:3306/springboot_mybatis_test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver

還有一個需要注意的,就是在選擇驅動的時候,如果前面初始化項目的時候,依賴中沒有加入 mysql-connector-java 這個以來,這裏配置是會報紅的,點擊或者快捷會提示你引入依賴,而就像下面這樣,默認不指定版本的依賴是 8.x 版本的 mysql-connector-java

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

所以配置時就要選擇 com.mysql.cj.jdbc.Driver

如果使用舊版的就會提示,com.mysql.jdbc.Driver 過時了

Loading class com.mysql.jdbc.Driver'. This is deprecated. The new driver class iscom.mysql.cj.jdbc.Driver’. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.

如果想要用舊版,你也可以顯性的指定 mysql-connector-java 版本

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.26</version>
</dependency>

(3) 使用 JdbcTemplate 進行 CURD

經過簡單的配置,其實已經可以進行原生 JDBC 的增刪改查了,原生的確實有點繁瑣,Spring 已經給我們進行了一定的簡化,也就是 JdbcTemplate,這個我們應該也很早就用過了

A:查詢

關於查詢,我給大家展示兩種方式,一種就是如果我們存在實體對應數據庫中的內容,還有一種就是沒有對應的實體的查詢方式,同時別忘記注入 JdbcTemplate

  • 有實體:在query中new 一個 BeanPropertyRowMapper,也就是讓 JdbcTemplate 幫我們把查詢結果集ResultSet 的每一行結果都使用 BeanPropertyRowMapper.mapRow() 方法,轉化成我們想要的Java類對象
  • 沒有實體:使用queryForList方法,返回一個集合,集合中是一個個 map
@Controller
@RequestMapping("/jdbc")
public class JdbcTemplateController {
    @Autowired
    JdbcTemplate jdbcTemplate;
    
	//有對應實體
    @RequestMapping("/userList")
    public void userList(){
        String sql = "select * from user";
        ArrayList<User> users = (ArrayList<User>) jdbcTemplate.query(sql,
                new BeanPropertyRowMapper<User>(User.class));
        for (User user : users){
            System.out.println(user);
        }
    }
    
    //沒有對應實體
    @RequestMapping("/userList")
    @ResponseBody
    public List<Map<String, Object>> userList(){
        String sql = "select * from user";
        List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
        return maps;
    }
}

這是查到的對象集合

User{uid=1, username='zhangsan', password='666', nickname='飛翔的企鵝'}
User{uid=2, username='lisi', password='666', nickname='傷心小男孩'}

這是查到的map集合

[{"uid":1,"username":"zhangsan","password":"666","nickname":"飛翔的企鵝"},{"uid":2,"username":"lisi","password":"666","nickname":"傷心小男孩"}]

B:插入

@RequestMapping("/addUser")
@ResponseBody
public String addUser(){
    //插入語句,注意時間問題
    String sql = "insert into user(uid, username,password,nickname) values (NULL,'wangwu','888','王五暱稱')";
    jdbcTemplate.update(sql);
    //查詢
    return "添加用戶成功";
}

C:修改

//修改用戶信息
@RequestMapping("/updateUser/{uid}")
@ResponseBody
public String updateUser(@PathVariable("uid") int uid){
    //插入語句
    String sql = "update user set username=?,password=?,nickname=? where uid="+ uid;
    //數據
    String[] s = new String[3];
    s[0] = "jack";
    s[1] = "666";
    s[2] = "傑克";
    jdbcTemplate.update(sql,s);
    //查詢
    return "修改用戶信息成功";
}

D:刪除

//刪除用戶
@RequestMapping("/deleteUser/{uid}")
@ResponseBody
public String delUser(@PathVariable("uid") int uid){
    //插入語句
    String sql = "delete from user where uid=?";
    jdbcTemplate.update(sql,uid);
    //查詢
    return "刪除用戶成功";
}

(二) 整合 Druid

(1) SpringBoot 默認連接池

首先要知道 Druid 是阿里的開源的一款數據庫連接池,而連接池就是用來解決數據庫建立關閉等消耗資源,而影響性能的問題的,我們以前應該用過挺多種的,例如 C3P0,或者 DBCP等等

而 SpringBoot 默認是有配置數據源的,我們可以簡單看一下,就在前面 JDBC 的例子上看,在測試類中看一下

@SpringBootTest
class Springboot08JdbcApplicationTests {

    @Autowired
    DataSource dataSource;

    @Test
    void contextLoads() throws SQLException {
        // 數據源
        System.out.println(dataSource.getClass());
        //獲得連接
        Connection connection = dataSource.getConnection();
        System.out.println(connection);
        connection.close();
    }

}

看一下打印的結果

class com.zaxxer.hikari.HikariDataSource
HikariProxyConnection@118492650 wrapping com.mysql.cj.jdbc.ConnectionImpl@712cfb63

可以看到,SpringBoot 默認使用的是 Hikari 連接池,如果想要看一下相關源碼,可以去看一下這兩個類

DataSourceAutoConfiguration、DataSourceConfiguration

這個數據庫連接池,現在號稱速度最快,不過 Hikari 和 Druid 都是很優秀的數據庫連接池,Druid 不過功能也更加多一些,它還有一些例如統計或者 sql 攔截等等功能,後面整合就可以看到

(2) 引入依賴

首先在 Pom 中添加 Druid 的依賴,可以去下列網址看一下最新的版本

https://mvnrepository.com/artifact/com.alibaba/druid

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.22</version>
</dependency>

(3) 修改配置

接着在配置中使用 spring.datasource.type 指定自定義的數據源類型,值就要用的連接池實現的完全限定名,例如: com.alibaba.druid.pool.DruidDataSource

我們用接着用上面的 yml 配置,而指定完 Druid 後,進行進行一些默認的配置,例如連接初始化大小、最大最小連接數等等嗎,具體內容不展開講,對着官方文檔很好理解

spring:
  datasource:
    username: root
    password: root99
    url: jdbc:mysql://localhost:3306/springboot_mybatis_test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver
    # 自定義數據源
    type: com.alibaba.druid.pool.DruidDataSource 

    #druid 數據源專有配置
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true

    #配置監控統計攔截的filters
    #stat:監控統計、log4j:日誌記錄、wall:防禦sql注入
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

如果運行的時候報錯 java.lang.ClassNotFoundException: org.apache.log4j.Priority
則導入 log4j 依賴即可

地址:https://mvnrepository.com/artifact/log4j/log4j

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

(4) 綁定自定義配置參數

寫了上面的參數,還是有問題的,例如下面的初始化大小,或者最大最小連接數等一些私有化的配置是不會生效的,因爲Spring Boot 默認是不注入這些屬性值的,所以我們需要自己進行綁定

創建一個包爲 config ,創建 DruidConfig 類

我們首先要做的就是將全局配置文件中的那些 Druid 的配置綁定到 com.alibaba.druid.pool.DruidDataSource,這樣就可以生效了 (@ConfigurationProperties

然後將自定義的 Druid數據源添加到容器中,這樣就不需要 SpringBoot 自己創建了

@Configuration
public class DruidConfig {

    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource druidDataSource() {
        return new DruidDataSource();
    }

}

可以簡單測試一下是不是生效了

@SpringBootTest
class Springboot08JdbcApplicationTests {

    @Autowired
    DataSource dataSource;

    @Test
    void contextLoads() throws SQLException {
        // 數據源
        System.out.println(dataSource.getClass());
        //獲得連接
        Connection connection = dataSource.getConnection();
        System.out.println(connection);

        DruidDataSource druidDataSource = (DruidDataSource) dataSource;
        System.out.println("數據源最大連接數:" + druidDataSource.getMaxActive());
        System.out.println("數據源初始化連接數:" + druidDataSource.getInitialSize());
		//關閉連接
        connection.close();
    }

}

運行能看出,那些基本的配置都是生效了的

class com.alibaba.druid.pool.DruidDataSource
com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@74e6094b
druidDataSource 數據源最大連接數:20
druidDataSource 數據源初始化連接數:5

(5) 配置數據源監控

還有一個非常有特點的功能,那就是 Druid 的數據源監控,提供了一個後臺管理頁面

繼續在上面新建的 DruidConfig 配置類中增加內容

  • 這裏採用 Spring Boot 註冊 Servlet 方式,是因爲內置 Servlet 容器時沒有web.xml文件,都是一些固定的寫法

  • 關於例如用戶名等的參數,可以再Druid下 StatViewServlet 的父類 ResourceServlet 中找到

  • 還可以設置訪問人員與禁止訪問人員相關的

@Bean
public ServletRegistrationBean statViewServlet() {
    ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
    
    Map<String, String> initParams = new HashMap<>();
    initParams.put("loginUsername", "admin"); //後臺管理界面的登錄賬號
    initParams.put("loginPassword", "admin888"); //後臺管理界面的登錄密碼

    //initParams.put("allow", "localhost"):表示只有本機可以訪問
    //initParams.put("allow", ""):表示後臺允許所有訪問
    initParams.put("allow", "");

    //設置初始化參數
    bean.setInitParameters(initParams);
    return bean;
}

來訪問一下:

我們在地址欄輸入 http://localhost:8080/druid/ 下的任何路徑都會訪問後臺 login 頁面,登錄後可以看到一些例如 SQL 監控等等功能

(三) 整合 MyBatis

這一塊基本沒什麼難題,依舊是一張普通的用戶表測試一下,爲了看起來舒服點,這裏沒有指定 Druid,如果需要,自己按上面加上就可以了

(1) 引入依賴

引入 mybatis 啓動器,以及連接 MySQL 驅動

<!--mybatis起步依賴-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.0.1</version>
</dependency>

<!-- MySQL連接驅動 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

(2) 配置數據庫

依舊是配置用戶名密碼登基本參數,還有就是關於 mybatis 的一些配置,配置 mapper-locations 就可以找到 recourses 下的自己創建 mapper 文件夾下的 xml 映射文件, type-aliases-package 配置的是放這我們的實體的包,也就是掃描包

spring:
  datasource:
    username: root
    password: root99
    url: jdbc:mysql://localhost:3306/springboot_mybatis_test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver
#    type: com.alibaba.druid.pool.DruidDataSource # 自定義數據源
  
mybatis:
  mapper-locations: classpath:mapper/*Mapper.xml
  type-aliases-package: cn.ideal.pojo

(3) 創建實體

public class User {
    private Long uid;
    private String username;
    private String password;
    private String nickname;
    ...... get set toString
}

(4) 編寫 Mapper 和 Mapper.xml

UserMapper

@Mapper
public interface UserMapper {
    public List<User> queryAllUser();
}

UserMapper.xml

此文件路徑 src\main\resources\mapper\UserMapper.xml

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="cn.ideal.mapper.UserMapper">
    <select id="queryAllUser" resultType="cn.ideal.domain.User">
        select * from user
    </select>
</mapper>

(5) 測試

@Controller
public class MybatisController {
    @Autowired
    private UserMapper userMapper;

    @RequestMapping("/queryAllUser")
    @ResponseBody
    public List<User> queryUser() {
        List<User> users = userMapper.queryAllUser();
        return users;
    }
}

返回結果:

[{"uid":1,"username":"zhangsan","password":"666","nickname":"飛翔的企鵝"},{"uid":2,"username":"lisi","password":"666","nickname":"傷心小男孩"},{"uid":3,"username":"jack","password":"666","nickname":"傑克"}]

(四) 整合 Redis

趁着寫完了整合 MyBatis,順便簡單提及一下 Redis,因爲一會測試的時候,可以用上整合好的 MyBatis,用來判斷數據來自數據庫還是緩存

(1) 引入依賴

<!-- 配置使用redis啓動器 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

(2) 修改配置

這裏用 properties 都一樣,隨意

spring:
  redis:
    host: 127.0.0.1
    port: 6379

端口是 Redis 默認的,這時候同時可以打開 Redis 的客戶端,裝過的在目錄下找就好了 redis-server.exe

(3) 通過RedisTemplate測試Redis

直接在測試類中測試吧,下面的內容就是,第一次訪問從數據庫查,然後把數據寫入緩存,第二次因爲,緩存中已經已經有數據了,所以就從緩存中查找了

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Springboot03MybatisApplication.class)
public class RedisTest {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Test
    public void test() throws JsonProcessingException {
        //從redis中查
        String userLists = redisTemplate.boundValueOps("user.queryAllUser").get();
        //如果redis中沒內容
        if (null == userLists) {
            //查數據庫數據
            List<User> all = userMapper.queryAllUser();
            //轉json
            ObjectMapper om = new ObjectMapper();
            userLists = om.writeValueAsString(all);
            //將數據存儲到redis中,下次在查詢直接從redis中獲得數據,不查數據庫
            redisTemplate.boundValueOps("user.queryAllUser").set(userLists);
            System.out.println("這些數據從數據庫獲得!!!");
        } else {
            System.out.println("這些數據從redis緩存中獲得!!!");
        }
        System.out.println(userLists);
    }

}

執行結果

第一次

這些數據從數據庫獲得!!!
[{"uid":1,"username":"zhangsan","password":"666","nickname":"飛翔的企鵝"},{"uid":2,"username":"lisi","password":"666","nickname":"傷心小男孩"},{"uid":3,"username":"jack","password":"666","nickname":"傑克"}]

第二次

這些數據從redis緩存中獲得!!!
[{"uid":1,"username":"zhangsan","password":"666","nickname":"飛翔的企鵝"},{"uid":2,"username":"lisi","password":"666","nickname":"傷心小男孩"},{"uid":3,"username":"jack","password":"666","nickname":"傑克"}]

(五) 結尾

如果文章中有什麼不足,歡迎大家留言交流,感謝朋友們的支持!

如果能幫到你的話,那就來關注我吧!如果您更喜歡微信文章的閱讀方式,可以關注我的公衆號

在這裏的我們素不相識,卻都在爲了自己的夢而努力 ❤

一個堅持推送原創開發技術文章的公衆號:理想二旬不止

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章