04 SpringBoot對資料庫的支援
文章目錄
簡介
Spring Data
專案是Spring用來解決資料訪問問題的一攬子解決方案
Spring Data提供了統一的API,對資料儲存技術進行支援
不同的持久層技術,有不同的Spring Data子專案
這些子專案都通過Spring Data Commons專案來實現
Spring DataCommons讓我們在使用關係型或非關係型資料庫技術時,都使用基於Spring的統一標準
包含:CRUD、查詢、排序、分頁
常用子專案
- Spring Data JPA
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-jpa -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</ artifactId>
<version>1.11.10.RELEASE</version>
</dependency>
- Spring Data MongoDB
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-mongodb -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.10.10.RELEASE</version>
</dependency>
- Spring Data Neo4J
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-neo4j -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j</artifactId>
<version>5.0.3.RELEASE</version>
</dependency>
- Spring Data Redis
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-redis -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
- Spring Data Solr
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-solr -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-solr</artifactId>
<version>3.0.3.RELEASE</version>
</dependency>
- Spring For Apache Hadoop
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-hadoop -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-hadoop</artifactId>
<version>2.5.0.RELEASE</version>
</dependency>
- Spring Data GemFire
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-gemfire -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-gemfire</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
- Spring Data REST WebMVC
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-rest-webmvc -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-rest-webmvc</artifactId>
<version>3.0.3.RELEASE</version>
</dependency>
- Spring Data Couchbase
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-couchbase -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase</artifactId>
<version>3.0.3.RELEASE</version>
</dependency>
- Spring Data Elasticsearch
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-elasticsearch -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>3.0.3.RELEASE</version>
</dependency>
- Spring Data For Apache Cassandra Core
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-cassandra -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-cassandra</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
Repository介面
package org.springframework.data.repository;
import java.io.Serializable;
public interface Repository<T, ID extends Serializable> {
}
Repository根介面接收JPA領域類和領域類的id型別作為型別引數
CrudRepository
CrudRepository子介面定義了和CRUD相關操作的內容
package org.springframework.data.repository;
import java.io.Serializable;
@NoRepositoryBean
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
<S extends T> S save(S entity);
<S extends T> Iterable<S> save(Iterable<S> entities);
T findOne(ID id);
boolean exists(ID id);
Iterable<T> findAll();
Iterable<T> findAll(Iterable<ID> ids);
long count();
void delete(ID id);
void delete(T entity);
void delete(Iterable<? extends T> entities);
void deleteAll();
}
PagingAndSortingRepository
PagingAndSortingRepository子介面定義了分頁、排序相關的內容
package org.springframework.data.repository;
import java.io.Serializable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
/**
* Extension of {@link CrudRepository} to provide additional methods to retrieve entities using the pagination and
* sorting abstraction.
*
* @author Oliver Gierke
* @see Sort
* @see Pageable
* @see Page
*/
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {
/**
* Returns all entities sorted by the given options.
*
* @param sort
* @return all entities sorted by the given options
*/
Iterable<T> findAll(Sort sort);
/**
* Returns a {@link Page} of entities meeting the paging restriction provided in the {@code Pageable} object.
*
* @param pageable
* @return a page of entities
*/
Page<T> findAll(Pageable pageable);
}
小結
不同的資料訪問技術提供了不同的Repository
如:Spring Data JPA有JpaRepository;Spring Data MongoDB有MongoRepository
Spring Data專案有一個激動人心的功能,可以根據屬性名進行計數、刪除、查詢等方法的操作
關鍵字 | 方法命名 | sql where字句 |
---|---|---|
And | findByNameAndPwd | where name= ? and pwd =? |
Or | findByNameOrSex | where name= ? or sex=? |
Is,Equals | findById,findByIdEquals | where id= ? |
Between | findByIdBetween | where id between ? and ? |
LessThan | findByIdLessThan | where id < ? |
LessThanEquals | findByIdLessThanEquals | where id <= ? |
GreaterThan | findByIdGreaterThan | where id > ? |
GreaterThanEquals | findByIdGreaterThanEquals | where id > = ? |
After | findByIdAfter | where id > ? |
Before | findByIdBefore | where id < ? |
IsNull | findByNameIsNull | where name is null |
isNotNull,NotNull | findByNameNotNull | where name is not null |
Like | findByNameLike | where name like ? |
NotLike | findByNameNotLike | where name not like ? |
StartingWith | findByNameStartingWith | where name like ‘?%’ |
EndingWith | findByNameEndingWith | where name like ‘%?’ |
Containing | findByNameContaining | where name like ‘%?%’ |
OrderBy | findByIdOrderByXDesc | where id=? order by x desc |
Not | findByNameNot | where name <> ? |
In | findByIdIn(Collection<?> c) | where id in (?) |
NotIn | findByIdNotIn(Collection<?> c) | where id not in (?) |
True | findByAaaTue | where aaa = true |
False | findByAaaFalse | where aaa = false |
IgnoreCase | findByNameIgnoreCase | where UPPER(name)=UPPER(? |
find方法是查詢,如果是計數,則為count,刪除,則為delete
限制結果數量:top和first關鍵字,如,findFirst10ByName,findTop10ByName
Spring Data JPA
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
- 資料來源
spring:
datasource:
url: jdbc:mysql://localhost:3306/tdk?useSSL=false&useUnicode=true&characterEncoding=utf8
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
jackson:
serialization: true
自動配置
SpringBoot自動開啟了註解事務的支援(@EnableTransactionManagement
)
還配置了一個JdbcTemplate
Spring還提供了一個初始化資料的功能,放在類路徑下的schema.sql
自動初始化表結構,data.sql
自動填充表資料
SpringData對JPA的自動配置放在org.springframework.boot.autoconfigure.orm.jpa
預設的JPA實現是Hibernate
配置JPA的字首為:spring.jpa
自動掃描註解有@Entity的實體類
在Web專案中,我們經常遇到控制器或頁面訪問資料的時候出現會話連線關閉的錯誤
這個時候,我們會配置一個Open EntityManager(Session)In View
這個過濾器
SpringBoot為我們自動配置了OpenEntityManagerInViewInterceptor
這個Bean,
並且已經註冊到SpringMVC攔截器。
無需手動開啟
@EnableJpaRepositories
案例
- pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
- domain
package org.zln.spb.demo01.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
/**
* @Author 張柳寧
* @Description
* @Date Create in 2018/1/31
* @Modified By:
*/
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@NamedQuery(name = "Person.withNameAndAddressNamedQuery",
query = "select p from Person p where p.name = ?1 and p.address = ?2")
public class Person {
@Id
@GeneratedValue
private Long id;
private String name;
private Integer age;
private String address;
}
- dao
package org.zln.spb.demo01.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.zln.spb.demo01.domain.Person;
import java.util.List;
/**
* @Author 張柳寧
* @Description
* @Date Create in 2018/1/31
* @Modified By:
*/
public interface PersonDao extends JpaRepository<Person,Long> {
List<Person> findByAddress(String address);
Person findByNameAndAddress(String name,String address);
@Query("select p from Person p where p.name = :name and p.address = :address")
Person withNameAndAddressQuery(@Param("name") String name,@Param("address") String address);
Person withNameAndAddressNamedQuery(String name,String address);
List<Person> findByNameLike(String name);
}
- 測試
package org.zln.spb.demo01.dao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.zln.spb.demo01.domain.Person;
import java.util.List;
import static org.junit.Assert.*;
/**
* @Author 張柳寧
* @Description
* @Date Create in 2018/1/31
* @Modified By:
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonDaoTest {
@Autowired
private PersonDao personDao;
@Test
public void findByAddress() {
personDao.findByAddress("地址");
}
@Test
public void findByNameAndAddress() {
personDao.findByNameAndAddress("姓名","地址");
}
@Test
public void withNameAndAddressQuery() {
personDao.withNameAndAddressQuery("姓名","地址");
}
@Test
public void withNameAndAddressNamedQuery() {
personDao.withNameAndAddressNamedQuery("姓名","地址");
}
@Test
public void findByNameLike() {
List<Person> personList = personDao.findByNameLike("%name%");
System.out.println(personList);
}
}
- 排序
personList = personDao.findAll(new Sort(Sort.Direction.DESC,"age"));
- 分頁查詢
Page<Person> people = personDao.findAll(new PageRequest(2,3));
for (Person person:people){
System.out.println(person);
}
小結
對於大多數的SQL,其實都是非常簡單的單表查詢
這個時候使用IDEA對Hibernate的自動生成程式碼,非常方便的
對於一些複雜SQL,再考慮使用MyBatis或者JdbcTemplate
整合H2資料庫
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
server:
port: 8000
spring:
jpa:
generate-ddl: false
show-sql: true
hibernate:
ddl-auto: none
datasource: # 指定資料來源
platform: h2 # 指定資料來源型別
schema: classpath:schema.sql # 指定h2資料庫的建表指令碼
data: classpath:data.sql # 指定h2資料庫的資料指令碼
logging: # 配置日誌級別,讓hibernate打印出執行的SQL
level:
root: INFO
org.hibernate: INFO
org.hibernate.type.descriptor.sql.BasicBinder: TRACE
org.hibernate.type.descriptor.sql.BasicExtractor: TRACE
HikariDataSource資料來源
配置
# jdbc_config datasource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/datebook?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull
spring.datasource.username=root
spring.datasource.password=root
# Hikari will use the above plus the following to setup connection pooling
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.maximum-pool-size=15
spring.datasource.hikari.auto-commit=true
spring.datasource.hikari.idle-timeout=30000
spring.datasource.hikari.pool-name=DatebookHikariCP
spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.connection-test-query=SELECT 1
spring:
profiles:
active: prod
datasource:
# 使用高效能資料來源
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
hikari:
minimum-idle: 15
maximum-pool-size: 50
idle-timeout: 30000
pool-name: DatebookHikariCP
maxLifetime: 40000 # 這個值要配置的比mysql的wait_timeout小,預設值是30分鐘。但是不得配置少於30秒,佛足額就會重置回預設值
connection-timeout: 30000
connection-test-query: SELECT 1
connection-init-sql: set names utf8mb4
validation-timeout: 5000
springboot 2.0 預設連線池就是Hikari了,所以引用parents後不用專門加依賴
java配置
Java配置資料來源
public HikariDataSource dataSourceConf(MutiDataSourceProperties dataSource) {
//資料來源配置資訊
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setJdbcUrl(dataSource.getUrl());
hikariConfig.setUsername(dataSource.getUsername());
hikariConfig.setPassword(dataSource.getPassword());
hikariConfi