二、spring Boot構建的Web應用中,基於MySQL數據庫的幾種數據庫連接方式進行介紹


 包括JDBC、JPA、MyBatis、多數據源和事務。

一、JDBC 連接數據庫

1、屬性配置文件(application.properties)

spring.datasource.url=jdbc:mysql://localhost:3306/test spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.jdbc.Driver

如果使用JNDI,則可以替代 spring.datasource 的 url、username、password,如:

spring.datasource.jndi-name=java:tomcat/datasources/example 

 

值得一提的是,無論是Spring Boot默認的DataSource配置還是你自己的DataSource bean,都會引用到外部屬性文件中的屬性配置。所以假設你自定義的DataSource bean,你可以在定義bean時設置屬性,也可以在屬性文件中,以“spring.datasource.*”的方式使屬性配置外部化。

2、pom.xml 配置maven依賴

        <!-- MYSQL --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- Spring Boot JDBC --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency>

3、Java代碼范例

StudentService.java

package org.springboot.sample.service; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import org.springboot.sample.entity.Student; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Service;  @Service public class StudentService { @Autowired private JdbcTemplate jdbcTemplate; public List<Student> getList(){ String sql = "SELECT ID,NAME,SCORE_SUM,SCORE_AVG, AGE FROM STUDENT"; return (List<Student>) jdbcTemplate.query(sql, new RowMapper<Student>(){ @Override public Student mapRow(ResultSet rs, int rowNum) throws SQLException { Student stu = new Student(); stu.setId(rs.getInt("ID")); stu.setAge(rs.getInt("AGE")); stu.setName(rs.getString("NAME")); stu.setSumScore(rs.getString("SCORE_SUM")); stu.setAvgScore(rs.getString("SCORE_AVG")); return stu; } }); } }

Student.java 實體類

package org.springboot.sample.entity; import java.io.Serializable;  public class Student implements Serializable{ private static final long serialVersionUID = 2120869894112984147L; private int id; private String name; private String sumScore; private String avgScore; private int age; // 節省文章長度,get set 方法省略 }

StudentController.java

package org.springboot.sample.controller; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springboot.sample.entity.Student; import org.springboot.sample.service.StudentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/stu") public class StudentController { private static final Logger logger = LoggerFactory.getLogger(StudentController.class); @Autowired private StudentService studentService; @RequestMapping("/list") public List<Student> getStus(){ logger.info("從數據庫讀取Student集合"); return studentService.getList(); } }

本文對工程添加文件后工程結構圖: 
這里寫圖片描述

然后啟動項目,訪問地址: http://localhost:8080/myspringboot/stu/list 響應結果如下:

[
{
id: 1, name: "小明", sumScore: "252", avgScore: "84", age: 1 }, { id: 2, name: "小王", sumScore: "187", avgScore: "62.3", age: 1 }, { id: 3, name: "莉莉", sumScore: "", avgScore: "", age: 0 }, { id: 4, name: "柱子", sumScore: "230", avgScore: "76.7", age: 1 }, { id: 5, name: "大毛", sumScore: "", avgScore: "", age: 0 }, { id: 6, name: "亮子", sumScore: "0", avgScore: "0", age: 1 } 

連接池說明

Tomcat7之前,Tomcat本質應用了DBCP連接池技術來實現的JDBC數據源,但在Tomcat7之后,Tomcat提供了新的JDBC連接池方案,作為DBCP的替換或備選方案,解決了許多之前使用DBCP的不利之處,並提高了性能。詳細請參考:http://wiki.jikexueyuan.com/project/tomcat/tomcat-jdbc-pool.html

Spring Boot為我們准備了最佳的數據庫連接池方案,只需要在屬性文件(例如application.properties)中配置需要的連接池參數即可。 
我們使用Tomcat數據源連接池,需要依賴tomcat-jdbc,只要應用中添加了spring-boot-starter-jdbc 或 spring-boot-starter-data-jpa依賴,則無需擔心這點,因為將會自動添加 tomcat-jdbc 依賴。 
假如我們想用其他方式的連接池技術,只要配置自己的DataSource bean,即可覆蓋Spring Boot的自動配置。

請看我的數據源配置:

spring.datasource.url=jdbc:mysql://localhost:3306/test spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.max-idle=10 spring.datasource.max-wait=10000 spring.datasource.min-idle=5 spring.datasource.initial-size=5 spring.datasource.validation-query=SELECT 1 spring.datasource.test-on-borrow=false spring.datasource.test-while-idle=true spring.datasource.time-between-eviction-runs-millis=18800 spring.datasource.jdbc-interceptors=ConnectionState;SlowQueryReport(threshold=0)

配置過連接池的開發人員對這些屬性的意義都有所認識。

我們打開DEBUG日志輸出,logback.xml 中添加:

<logger name="org.springframework.boot" level="DEBUG"/>

然后啟動項目,注意觀察日志輸出,如下圖中會顯示自動啟用了連接池: 
這里寫圖片描述 
在上面的數據源配置中添加了過濾器,並設置了延遲時間為0(故意設置很低,實際項目中請修改):

spring.datasource.jdbc-interceptors=ConnectionState;SlowQueryReport(threshold=0)

這個時候,我們訪問 http://localhost:8080/myspringboot/stu/list 觀察日志,會發現框架自動將大於該時間的數據查詢進行警告輸出,如下:

 o.a.t.j.p.interceptor.SlowQueryReport : Slow Query Report SQL=SELECT ID,NAME,SCORE_SUM,SCORE_AVG, AGE FROM STUDENT; time=3 ms;

二、將介紹如何在spring Boot 工程中添加JPA作為持久化方式

修改 pom.xml 依賴

與上一篇介紹的 jdbc 不同的是 spring-boot-starter-jdbc 修改為 spring-boot-starter-data-jpa 即可,當然數據庫驅動包也是不可少的,如下:

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

 

注意:如果你想JDBC和JPA可以一起使用,Spring Boot 是支持的,你只需要把JDBC和JPA的依賴都添加在pom.xml 中即可。無需其他特殊處理,有關JDBC的使用介紹請看上一篇 “Spring-Boot JDBC 連接數據庫”。

修改屬性配置文件

在屬性配置文件中添加 JPA 相關屬性,注意這些並非必須,我們如果只添加dataSource 的 url\username\password\driver-class-name 也可以正常使用,有關JPA的其他配置都是可選的。

spring.jpa.database= spring.jpa.show-sql= spring.jpa.properties= spring.jpa.generate-ddl= spring.jpa.open-in-view= spring.jpa.database-platform= spring.jpa.hibernate.ddl-auto= spring.data.jpa.repositories.enabled= spring.jpa.hibernate.naming-strategy=

熟悉JPA的根據名字應基本知道這些分別的作用了。

傳統上,JPA實體類在persistence.xml文件中指定的。使用Spring Boot,這個文件是沒有必要的,因為它使用“實體掃描”,默認情況下主配置 @EnableAutoConfiguration 或 @SpringBootApplication 下面的所有包都將會被掃描。任何使用注解 @Entity, @Embeddable 或 @MappedSuperclass 的類都將被管理。

Java代碼實例

  • 一個接口
  • 一個Controller

我們創建一個接口 IScoreDao.Java ,然后我們繼承框架為我們提供好的接口 Repository 或 CrudRepository (CrudRepository 繼承自 Repository),其中為我們提供了對數據庫的基本操作方法。

package org.springboot.sample.dao; import java.util.List; import javax.transaction.Transactional; import org.springboot.sample.entity.Score; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; public interface IScoreDao extends CrudRepository<Score, Integer> { @Transactional @Modifying @Query("update Score t set t.score = :score where t.id = :id") int updateScoreById(@Param("score") float score, @Param("id") int id); @Query("select t from Score t ") List<Score> getList(); }

注意,如果你其中使用了修改、新增、刪除操作,則必須要在接口上面或者對應的方法上面添加 @Transactional 注解,否則會拋出異常。

實體類 Score.java

package org.springboot.sample.entity; import java.io.Serializable; import java.util.Date; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; /** * 成績 * */ @Entity @Table(name = "score") public class Score implements Serializable { private static final long serialVersionUID = 8127035730921338189L; @Id @GeneratedValue private int id; @Column(nullable = false, name="STUDENTID") // 這里說一下,我使用指定數據庫列的時候,使用小寫會不起作用,修改為大寫便正常了。不知道為何,如果遇到一樣問題的可以嘗試下。 private int stuId; @Column(nullable = false, name="SUBJECTNAME") private String subjectName; @Column(nullable = false) private float score; @Column(nullable = false, name="EXAMTIME") private Date examTime; // 省去get、set 方法(占用文章空間) }

ScoreController.java

package org.springboot.sample.controller; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springboot.sample.dao.IScoreDao; import org.springboot.sample.entity.Score; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/score") public class ScoreController { private static final Logger logger = LoggerFactory.getLogger(ScoreController.class); @Autowired private IScoreDao scoreService; @RequestMapping("/scoreList") public List<Score> getScoreList(){ logger.info("從數據庫讀取Score集合"); // 測試更新數據庫 logger.info("更新的行數:" + scoreService.updateScoreById(88.8f, 2)); scoreService.delete(23); return scoreService.getList(); } }

然后在瀏覽器訪問地址:http://localhost:8080/myspringboot/score/scoreList 測試


最后要說明的是,Spring 會自動為我們繼承CrudRepository接口的接口創建實現類。我們只需要在使用的時候直接使用注解 @Autowired 注入即可(IScoreDao 接口上也沒有必要增加 @Component 、 @Repository 等注解)。 
還有,我這里為了簡單起見,直接將操作數據庫的在Controller中使用,實際項目中,是不建議這樣做的,IScoreDao 的所屬角色是數據庫持久,我們還應當有 Service(如ScoreService) 來調用 IScoreDao 的方法,然后在Controller 中調用 Service 中的方法。原因是因為,我們數據庫訪問層,都是接口定義方法,上面注解注入SQL和參數,沒有具體的代碼邏輯處理。如果我們想在執行SQL之前或之后執行邏輯處理,只能在 Service 中或者Controller(不建議)中。 
我們嚴格按照這種方式去做(持久層只與SQL有關,通過接口定義無邏輯處理),這樣才是徹徹底底的持久層。越嚴格的規范制度,在某種程度上來說其實越有利於代碼的管理和項目代碼的迭代發展。

當然,如果你實在想要實現自己的 class 實現類,下面會附上一個實例代碼,在此之前,我們先看一個圖片: 
這里寫圖片描述

這個圖是Spring 使用動態代理創建的接口實例,可以看出,其使用的是 SimpleJpaRepository 類,所以如果我們實現自己的 Repository ,可以擴展 SimpleJpaRepository 並 實現自己的 factory-class 入手,這里不做詳解。注意凡事實現 Repository 接口的實現類都不需要添加 @Repository 注解,否則你會遇到問題。

本文介紹JPA 相比上一篇關於JDBC 的介紹增加的文件工程截圖為: 
工程結構截圖

熟悉其中一種持久數據的方法后,其他類似的都大同小異。

三、SpringBoot種配置MyBatis

其實mybatis官網在2015年11月底就已經發布了對SpringBoot集成的Release版本,Github上有代碼:https://github.com/mybatis/mybatis-spring-boot 
前面對JPA和JDBC連接數據庫做了說明,本文也是參考官方的代碼做個總結。

先說個題外話,SpringBoot默認使用 org.apache.tomcat.jdbc.pool.DataSource 
現在有個叫 HikariCP 的JDBC連接池組件,據說其性能比常用的 c3p0、tomcat、bone、vibur 這些要高很多。 
我打算把工程中的DataSource變更為HirakiDataSource,做法很簡單: 
首先在application.properties配置文件中指定dataSourceType

spring.datasource.type=com.zaxxer.hikari.HikariDataSource

然后在pom中添加Hikari的依賴

<dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <!-- 版本號可以不用指定,Spring Boot會選用合適的版本 --> </dependency>

言歸正傳,下面說在spring Boot中配置MyBatis。 
關於在Spring Boot中集成MyBatis,可以選用基於注解的方式,也可以選擇xml文件配置的方式。通過對兩者進行實際的使用,還是建議使用XML的方式(官方也建議使用XML)。

下面將介紹通過xml的方式來實現查詢,其次會簡單說一下注解方式,最后會附上分頁插件(PageHelper)的集成。

一、通過xml配置文件方式

1、添加pom依賴

<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <!-- 請不要使用1.0.0版本,因為還不支持攔截器插件,1.0.1-SNAPSHOT 是博主寫帖子時候的版本,大家使用最新版本即可 --> <version>1.0.1-SNAPSHOT</version> </dependency>

2、創建接口Mapper(不是類)和對應的Mapper.xml文件

定義相關方法,注意方法名稱要和Mapper.xml文件中的id一致,這樣會自動對應上 
StudentMapper.Java

package org.springboot.sample.mapper;

import java.util.List; import org.springboot.sample.entity.Student; /** * StudentMapper,映射SQL語句的接口,無邏輯實現 * */ public interface StudentMapper extends MyMapper<Student> { List<Student> likeName(String name); Student getById(int id); String getNameById(int id); }

MyMapper.java

package org.springboot.sample.config.mybatis;

import tk.mybatis.mapper.common.Mapper; import tk.mybatis.mapper.common.MySqlMapper; /** * 被繼承的Mapper,一般業務Mapper繼承它 * */ public interface MyMapper<T> extends Mapper<T>, MySqlMapper<T> { //TODO //FIXME 特別注意,該接口不能被掃描到,否則會出錯 }

StudentMapper.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="org.springboot.sample.mapper.StudentMapper"> <!-- type為實體類Student,包名已經配置,可以直接寫類名 --> <resultMap id="stuMap" type="Student"> <id property="id" column="id" /> <result property="name" column="name" /> <result property="sumScore" column="score_sum" /> <result property="avgScore" column="score_avg" /> <result property="age" column="age" /> </resultMap> <select id="getById" resultMap="stuMap" resultType="Student"> SELECT * FROM STUDENT WHERE ID = #{id} </select> <select id="likeName" resultMap="stuMap" parameterType="string" resultType="list"> SELECT * FROM STUDENT WHERE NAME LIKE CONCAT('%',#{name},'%') </select> <select id="getNameById" resultType="string"> SELECT NAME FROM STUDENT WHERE ID = #{id} </select> </mapper> 

3、實體類

package org.springboot.sample.entity; import java.io.Serializable; /** * 學生實體 * */ public class Student implements Serializable{ private static final long serialVersionUID = 2120869894112984147L; private int id; private String name; private String sumScore; private String avgScore; private int age; // get set 方法省略 }

4、修改application.properties 配置文件

mybatis.mapper-locations=classpath*:org/springboot/sample/mapper/sql/mysql/*Mapper.xml mybatis.type-aliases-package=org.springboot.sample.entity

5、在Controller或Service調用方法測試


    @Autowired private StudentMapper stuMapper; @RequestMapping("/likeName") public List<Student> likeName(@RequestParam String name){ return stuMapper.likeName(name); }

二、使用注解方式

查看官方Git上的代碼使用注解方式,配置上很簡單,使用上要對注解多做了解。至於xml和注解這兩種哪種方法好,眾口難調還是要看每個人吧。

1、啟動類(我的)中添加@MapperScan注解

@SpringBootApplication @MapperScan("sample.mybatis.mapper") public class SampleMybatisApplication implements CommandLineRunner { @Autowired private CityMapper cityMapper; public static void main(String[] args) { SpringApplication.run(SampleMybatisApplication.class, args); } @Override public void run(String... args) throws Exception { System.out.println(this.cityMapper.findByState("CA")); } }

2、在接口上使用注解定義CRUD語句

package sample.mybatis.mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import sample.mybatis.domain.City; /** * @author Eddú Meléndez */ public interface CityMapper { @Select("SELECT * FROM CITY WHERE state = #{state}") City findByState(@Param("state") String state); }

其中City就是一個普通Java類。 
關於MyBatis的注解,有篇文章講的很清楚,可以參考: http://blog.csdn.net/luanlouis/article/details/35780175

三、集成分頁插件

這里與其說集成分頁插件,不如說是介紹如何集成一個plugin。MyBatis提供了攔截器接口,我們可以實現自己的攔截器,將其作為一個plugin裝入到SqlSessionFactory中。 
Github上有位開發者寫了一個分頁插件,我覺得使用起來還可以,挺方便的。 
Github項目地址: https://github.com/pagehelper/Mybatis-PageHelper

下面簡單介紹下: 
首先要說的是,Spring在依賴注入bean的時候,會把所有實現MyBatis中Interceptor接口的所有類都注入到SqlSessionFactory中,作為plugin存在。既然如此,我們集成一個plugin便很簡單了,只需要使用@Bean創建PageHelper對象即可。

1、添加pom依賴

<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>4.1.0</version> </dependency>

2、新增MyBatisConfiguration.java

package org.springboot.sample.config; import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.github.pagehelper.PageHelper; /** * MyBatis 配置 * */ @Configuration public class MyBatisConfiguration { private static final Logger logger = LoggerFactory.getLogger(MyBatisConfiguration.class); @Bean public PageHelper pageHelper() { logger.info("注冊MyBatis分頁插件PageHelper"); PageHelper pageHelper = new PageHelper(); Properties p = new Properties(); p.setProperty("offsetAsPageNum", "true"); p.setProperty("rowBoundsWithCount", "true"); p.setProperty("reasonable", "true"); pageHelper.setProperties(p); return pageHelper; } }

3、分頁查詢測試

    @RequestMapping("/likeName") public List<Student> likeName(@RequestParam String name){ PageHelper.startPage(1, 1); return stuMapper.likeName(name); }

更多參數使用方法,詳見PageHelper說明文檔(上面的Github地址)。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM