SpringBoot零基礎詳解六:SpringBoot與數據訪問

六:SpringBoot與數據訪問

1:JDBC的配置和使用

1.1:創建jdbc環境

pom.xml文件如下:

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

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

1.2:jabc的配置文件配置--application.yml

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://10.40.129.44:3306/test?serverTimezone=UTC
    #com.mysql.jdbc.Driver 是5版本的驅動
    #com.mysql。cj.jdbc.Driver 是8版本的驅動
    #?serverTimezone=UTC 解決時區的報錯
    driver-class-name: com.mysql.jdbc.Driver

實驗:

最終我們使用的配置是

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://10.40.129.44:3306/test?serverTimezone=UTC
    #com.mysql.jdbc.Driver 是5版本的驅動
    #com.mysql。cj.jdbc.Driver 是8版本的驅動
    #?serverTimezone=UTC 解決時區的報錯
    driver-class-name: com.mysql.cj.jdbc.Driver

1.3:springboot鏈接數據庫的原理

數據源的相關配置都在DataSourceProperties裏面;ctrl+點擊配置文件中剛纔配置的屬性就可以進入;

1:參考DataSourceConfiguration ,根據配置創建數據源,springboot2.x默認使用hikari數據源;可以使用spring.datasource.type指定自定義的數據源類型;

2:springboot默認支持的數據源有

org.apache.commons.dbcp2.BasicDataSource,
com.zaxxer.hikari.HikariDataSource
org.apache.tomcat.jdbc.pool.DataSource

3:如果使用spring.datasource.type來自定義數據源

使用DataSourceBuilder創建數據源,利用反射創建響應type的數據源,並且綁定相關屬性

1.4:DataSourceInitializer:執行自定義建表sql語句

由他調用各種初始化方法

 最終執行的是DataSourceInitializer的方法

1:所以要在系統開始的時候執行建表語句,必須在配置文件中配置

2:而建表語句的 文件名爲:默認爲:schema.sql,schema-all.sql;源代碼設置在下面:

3:也可以在配置文件中指定建表語句sql的位置,源代碼如下

 設置如下:

 1.5:DataSourceInitializer:執行初始化插入sql語句

和上邊建表的設置一樣

1:要不然設置插入sql語句的文件名默認爲:schema.sql,schema-all.sql;源代碼設置在下面:

2:要不然設置

1.6:springboot使用JdbcTemplate來操作數據庫

JdbcTemplate將我們使用的JDBC的流程封裝起來,包括了異常的捕捉、SQL的執行、查詢結果的轉換等等。spring大量使用Template Method模式來封裝固定流程的動作,XXXTemplate等類別都是基於這種方式的實現。
    除了大量使用Template Method來封裝一些底層的操作細節,spring也大量使用callback方式類回調相關類別的方法以提供JDBC相關類別的功能,使傳統的JDBC的使用者也能清楚瞭解spring所提供的相關封裝類別方法的使用。

1:使用JdbcTemplate的execute()方法執行SQL語句

2:如果是UPDATE或INSERT,可以用update()方法。可以帶參數防止sql注入

3:使用JdbcTemplate進行查詢時,使用queryForXXX()等方法

例子:

//注入JdbcTemplate
    @Autowired
    JdbcTemplate jdbcTemplate;

    @ResponseBody
    @RequestMapping("/query")
    public Map<String,Object> query(){
        List<Map<String, Object>> maps = jdbcTemplate.queryForList("select * from department");

        Map<String,Object> reslut = new HashMap<>();
        reslut.put("date",maps);
        return reslut;
    }

結果是: 

 

2、整合Druid數據源

Druid是一個關係型數據庫連接池,它是阿里巴巴的一個開源項目。Druid支持所有JDBC兼容數據庫,包括了Oracle、MySQL、PostgreSQL、SQL Server、H2等。Druid在監控、可擴展性、穩定性和性能方面具有明顯的優勢。通過Druid提供的監控功能,可以實時觀察數據庫連接池和SQL查詢的工作情況。使用Druid連接池在一定程度上可以提高數據訪問效率。
 

2.1:導入diuid依賴

      <!-- 配置jdbc的依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>

        <!-- 配置mysql驅動的依賴 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!--    導入druid數據源    -->
        <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.22</version>
        </dependency>

2.2:在配置文件中配置配置數據源

由於springboot默認不支持druid數據源,需要配置type

和其它連接池一樣DRUID的DataSource類爲:com.alibaba.druid.pool.DruidDataSource,基本配置參數如下:

配置 缺省值 說明
name   配置這個屬性的意義在於,如果存在多個數據源,監控的時候可以通過名字來區分開來。 
如果沒有配置,將會生成一個名字,格式是:"DataSource-" + System.identityHashCode(this)
jdbcUrl   連接數據庫的url,不同數據庫不一樣。例如: 
mysql : jdbc:mysql://10.20.153.104:3306/druid2 
oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto
username   連接數據庫的用戶名
password   連接數據庫的密碼。如果你不希望密碼直接寫在配置文件中,可以使用ConfigFilter。詳細看這裏:https://github.com/alibaba/druid/wiki/%E4%BD%BF%E7%94%A8ConfigFilter
driverClassName 根據url自動識別 這一項可配可不配,如果不配置druid會根據url自動識別dbType,然後選擇相應的driverClassName(建議配置下)
initialSize 0 初始化時建立物理連接的個數。初始化發生在顯示調用init方法,或者第一次getConnection時
maxActive 8 最大連接池數量
maxIdle 8 已經不再使用,配置了也沒效果
minIdle   最小連接池數量
maxWait   獲取連接時最大等待時間,單位毫秒。配置了maxWait之後,缺省啓用公平鎖,併發效率會有所下降,如果需要可以通過配置useUnfairLock屬性爲true使用非公平鎖。
poolPreparedStatements false 是否緩存preparedStatement,也就是PSCache。PSCache對支持遊標的數據庫性能提升巨大,比如說oracle。在mysql下建議關閉。
maxOpenPreparedStatements -1 要啓用PSCache,必須配置大於0,當大於0時,poolPreparedStatements自動觸發修改爲true。在Druid中,不會存在Oracle下PSCache佔用內存過多的問題,可以把這個數值配置大一些,比如說100
validationQuery   用來檢測連接是否有效的sql,要求是一個查詢語句。如果validationQuery爲null,testOnBorrow、testOnReturn、testWhileIdle都不會其作用。
testOnBorrow true 申請連接時執行validationQuery檢測連接是否有效,做了這個配置會降低性能。
testOnReturn false 歸還連接時執行validationQuery檢測連接是否有效,做了這個配置會降低性能
testWhileIdle false 建議配置爲true,不影響性能,並且保證安全性。申請連接的時候檢測,如果空閒時間大於timeBetweenEvictionRunsMillis,執行validationQuery檢測連接是否有效。
timeBetweenEvictionRunsMillis   有兩個含義: 
1) Destroy線程會檢測連接的間隔時間2) testWhileIdle的判斷依據,詳細看testWhileIdle屬性的說明
numTestsPerEvictionRun   不再使用,一個DruidDataSource只支持一個EvictionRun
minEvictableIdleTimeMillis    
connectionInitSqls   物理連接初始化的時候執行的sql
exceptionSorter 根據dbType自動識別 當數據庫拋出一些不可恢復的異常時,拋棄連接
filters   屬性類型是字符串,通過別名的方式配置擴展插件,常用的插件有: 
監控統計用的filter:stat日誌用的filter:log4j防禦sql注入的filter:wall
proxyFilters  

類型是List<com.alibaba.druid.filter.Filter>,如果同時配置了filters和proxyFilters,是組合關係,並非替換關係

測試結果:

 

2.3:使用druid數據源-定製的數據源其他參數配置

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=Asia/Shanghai
    #com.mysql.jdbc.Driver 是5版本的驅動
    #com.mysql。cj.jdbc.Driver 是8版本的驅動
    #?serverTimezone=UTC 解決時區的報錯
    driver-class-name: com.mysql.cj.jdbc.Driver
#    設置此項,可以執行建表或者插入sql語句
#    initialization-mode: always
#    指定建表sql的文件名,這是個集合,可以設置多個
#    schema:
#      - classpath:department.sql
#    插入數據sql文件位置,這也是一個集合
#    data:
#      - classpath:insert.sql
    #配置druid數據源
    type: com.alibaba.druid.pool.DruidDataSource
    #   數據源其他配置
    #初始化連接池大小
    initialSize: 5
    #連接池最小活躍數
    minIdle: 5
    #連接池最大活躍數
    maxActive: 20
    #最大連接等待時間
    maxWait: 60000
    #配置間隔多久才進行一次檢測,檢測需要關閉的空閒連接,單位是毫秒
    timeBetweenEvictionRunsMillis: 60000
    #配置一個連接在池中最小生存的時間,單位是毫秒
    minEvictableIdleTimeMillis: 300000
    #驗證連接有效與否的SQL,不同的數據配置不同
    validationQuery: SELECT 1 FROM DUAL

    testWhileIdle: true
    #裏建議配置爲TRUE,防止取到的連接不可用
    testOnBorrow: false
    testOnReturn: false
    #打開PSCache,並且指定每個連接上PSCache的大小
    poolPreparedStatements: true
    #   配置監控統計攔截的filters,去掉後監控界面sql無法統計,'wall'用於防火牆
    filters: stat,wall,logback
    #打開PSCache,並且指定每個連接上PSCache的大小
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

按照上述druid數據源的參數對數據源進行配置

在Spring Boot中驅動配置信息沒有問題,但是連接池的配置信息不再支持這裏的配置項,即無法通過配置項直接支持相應的連接池;這裏列出的這些配置項可以通過定製化DataSource來實現。

目前Spring Boot中默認支持的連接池有dbcp,dbcp2, tomcat, hikari三種連接池。

由於Druid暫時不在Spring Bootz中的直接支持,故需要進行配置信息的定製:

效果如圖:

2.4:使用Druid數據源-利用web.xml配置druid的web監控和攔截器

<servlet> 
     <servlet-name>DruidStatView</servlet-name> 
     <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class> 
 </servlet> 
 <servlet-mapping> 
     <servlet-name>DruidStatView</servlet-name> 
     <url-pattern>/druid/*</url-pattern> 
 </servlet-mapping> 
 <filter> 
  <filter-name>druidWebStatFilter</filter-name> 
  <filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class> 
  <init-param> 
   <param-name>exclusions</param-name> 
   <param-value>/public/*,*.js,*.css,/druid*,*.jsp,*.swf</param-value> 
  </init-param> 
  <init-param> 
   <param-name>principalSessionName</param-name> 
   <param-value>sessionInfo</param-value> 
  </init-param> 
  <init-param> 
   <param-name>profileEnable</param-name> 
   <param-value>true</param-value> 
  </init-param> 
 </filter> 
 <filter-mapping> 
  <filter-name>druidWebStatFilter</filter-name> 
  <url-pattern>/*</url-pattern> 
 </filter-mapping>

2.5:使用Druid數據源-利用ServletRegistrationBean配置druid的web監控和攔截器

在導入數據源的基礎上:

package com.wkl.springboot.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * Description:定製化配置druid數據源
 * Date:       2020/6/3 - 下午 12:01
 * author:     wangkanglu
 * version:    V1.0
 */
@Configuration
public class DruidConfig {

//    這個註解表示從配置文件中讀取這些配置信息
    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource druid(){
        return new DruidDataSource();
    }


    //配置Druid的監控
    //1、配置一個管理後臺的Servlet
    @Bean
    public ServletRegistrationBean statViewServlet(){
        //創建servlet註冊實體,StatViewServlet是druid的servlet
        ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*");

        Map<String,String> initParams = new HashMap<>();

        //設置控制檯管理用戶
        initParams.put("loginUsername","admin");
        initParams.put("loginPassword","123456");
        ////設置ip白名單
        initParams.put("allow","");//默認就是允許所有訪問
        //設置ip黑名單,如果allow與deny共同存在時,deny優先於allow
        initParams.put("deny","");

        bean.setInitParameters(initParams);

        return bean;
    }

    //2、配置一個web監控的filter

    @Bean
    public FilterRegistrationBean webStatFilter(){
        //創建過濾器
        FilterRegistrationBean bean = new FilterRegistrationBean();
        bean.setFilter(new WebStatFilter());

        Map<String,String> initParams = new HashMap<>();

        //忽略過濾的形式
        initParams.put("exclusions","*.js,*.css,/druid/*");

        bean.setInitParameters(initParams);
        //設置過濾器過濾路徑
        bean.setUrlPatterns(Arrays.asList("/*"));

        return bean;
    }
}

效果:

訪問http://127.0.0.1:8088/druid即可登錄

同時也可以監控我們系統內接口等邏輯處理類,執行的sql可以監控各種信息

 

3:整合MyBatis

 3.1:導入mybatis自己的依賴

        <!--   引入mybatis自己的依賴     -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>

圖解:

3.2:使用mybatis的步驟

1:配置數據源屬性(見上一章節)

2:數據庫創建表

3:創建javabean

 

3.3:使用註解版mybatis

指定這是操作數據庫的mapper

@Mapper
public interface DepartemetMapper {

    @Select("select * from department where id = #{id}")
    Department getDepartment(Integer id);

    //Options標註告訴系統,改id字段爲自增的
    @Options(useGeneratedKeys = true,keyProperty = "id")
    @Insert("insert into department(departmentName) values(#{departmentName})")
    int insertDept(Department department);

    @Delete("delete from department where id = #{id}")
    int deletDept(Integer id);

    @Update("update department set departmentName = #{departmentName} where id = #{id}")
    int updateDept(Department department);
}

創建接口訪問的Controller

@RestController
public class DepartmentController {

    @Autowired
    DepartemetMapper departemetMapper;

    @GetMapping("/dept/{id}")
    public Department getDept(@PathVariable("id") Integer id){
        return departemetMapper.getDepartment(id);
    }

    @GetMapping("/dept")
    public Department insertDept(Department department){
        departemetMapper.insertDept(department);
        return department;
    }
}

開啓駝峯命名法

#開啓mybatis的駝峯命名法
mybatis:
  configuration:
    map-underscore-to-camel-case: true

使用MapperScan批量掃描所有的Mapper接口;這樣就可以不用每個mapper類的都寫@Mapper註解

@MapperScan(value = "com.atguigu.springboot.mapper")
@SpringBootApplication
public class SpringBoot06DataMybatisApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringBoot06DataMybatisApplication.class, args);
	}
}

 

3.4:使用配置版mybatis

指定數據庫訪問mapper

@Mapper
public interface EmpployeeMapper {

    Empployee getEmp(int id);

    void insertEmp(Empployee empployee);
}

編寫mapper的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="com.wkl.springboot.mapper.EmpployeeMapper">
<!--    Empployee getEmp(int id);

    void insertEmp(Empployee empployee);-->
    <select id="getEmp" resultType="com.wkl.springboot.bean.Empployee">
        select * from employee where id = #{id}
    </select>

    <insert id="insertEmp" >
        insert into employee(lastName,email,gender,d_id) value (#{lastName},#{email},#{gender},#{dId})
    </insert>

</mapper>

編寫mybatis的配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--    解決關於mybatis的駝峯問題-->
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
</configuration>

在配置文件中配置上述的配置文件位置

mybatis:
#  configuration:
#    map-underscore-to-camel-case: true
  config-location: classpath:mybatis/mybatis_config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml

編寫Controller

@RestController
public class EmpController {

    @Autowired
    EmpployeeMapper empployeeMapper;

    @GetMapping("/emp/{id}")
    public Empployee getDept(@PathVariable("id") Integer id){
        return empployeeMapper.getEmp(id);
    }
}

4:整合SpringData jpa

4.1、SpringData簡介

4.2:springboot使用SpringData JPA的流程

JPA:ORM(Object Relational Mapping);

1:引入依賴

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

2:編寫一個實體類(bean)和數據表進行映射,並且配置好映射關係;

package com.wkl.springboot;


import javax.persistence.*;

/**
 * Description:
 * Date:       2020/6/7 - 上午 1:34
 * author:     wangkanglu
 * version:    V1.0
 */
//使用JPA註解配置映射關係
@Entity //告訴JPA這是一個實體類(和數據表映射的類)
@Table(name="tab_user") //@Table來指定和哪個數據表對應;如果省略默認表名就是類名小寫user
public class entity {
    @Id //這是一個主鍵
    @GeneratedValue(strategy = GenerationType.IDENTITY) //自增主鍵
    private Integer id;
    @Column(name = "last_name",length = 50) //這是和數據表對應的一個列
    private String lastName;
    @Column //省略默認列名就是屬性名
    private String email;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

3:編寫一個Dao接口來操作實體類對應的數據表(Repository)

package com.wkl.springboot.repository;

import com.wkl.springboot.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * Description:
 * Date:       2020/6/7 - 上午 1:46
 * author:     wangkanglu
 * version:    V1.0
 */
//繼承JpaRepository來完成對數據庫的操作
//													  表的類,主鍵類型
public interface UserReopsitory extends JpaRepository<User, Integer> {
    
}

4:配置文件中基本的配置JpaProperties

5:創建Controller

package com.wkl.springboot.controller;

import com.wkl.springboot.entity.User;
import com.wkl.springboot.repository.UserReopsitory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

/**
 * Description:
 * Date:       2020/6/7 - 上午 1:51
 * author:     wangkanglu
 * version:    V1.0
 */
@RestController
public class UserController {

    @Autowired
    UserReopsitory userReopsitory;

    @GetMapping("/user/{id}")
    public User getUser(@PathVariable("id")Integer id){
        return userReopsitory.getOne(id);
    }

    @GetMapping("/user")
    public User insertUser(User user){
        User save = userReopsitory.save(user);
        return save;
    }
}

6:使用getUser方法報500錯誤

錯誤原因是:在轉化成json的時候,fasterxml.jackson將對象轉換爲json報錯,發現有字段爲null。
解決方案:實體類上添加

@JsonIgnoreProperties(value = { "hibernateLazyInitializer"})

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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