Spring Boot可以自動配置嵌入式H2, HSQL和Derby數據庫。您無需提供任何連接URL。您只需要包含要使用的嵌入式數據庫的構建依賴項即可。
典型的嵌入式數據庫POM依賴配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>runtime</scope>
</dependency>
聲明對Spring Data模塊的依賴關系
<dependencies>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<dependencies>
連接到生產數據庫(MySQL)
application.properties:
spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=root
spring.datasource.password=passwd
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
至少應該通過設置spring.datasource.url 屬性來指定URL 。否則,Spring Boot會嘗試自動配置嵌入式數據庫
通常不需要指定driver-class-name,因為Spring Boot可以從URL推斷它的驅動類型
Spring Data Repositories
核心概念
Spring Data存儲庫抽象中的中央接口是Repository。它將域類(對應數據庫中的表或者NOSQL中的文檔)以及域類的ID類型(主鍵)作為類型參數進行管理。此接口主要用作標記接口,用于捕獲要使用的類型,并幫助您發現擴展此接口的接口。CrudRepository則規定了對于正在管理的實體類復雜的CRUD功能
CrudRepository接口
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
<S extends T> S save(S entity);
Optional<T> findById(ID primaryKey);
Iterable<T> findAll();
long count();
void delete(T entity);
boolean existsById(ID primaryKey);
// … 其他
}
- 保存給定的實體。
- 返回由給定ID標識的實體。
- 返回所有實體。
- 返回實體數量。
- 刪除給定的實體。
- 指示是否存在具有給定ID的實體。
PagingAndSortingRepository接口
public interface PagingAndSortingRepository<T, ID extends Serializable>
extends CrudRepository<T, ID> {
Iterable<T> findAll(Sort sort);
Page<T> findAll(Pageable pageable);
}
要訪問User頁面大小為20 的第二頁,您可以執行以下操作:
PagingAndSortingRepository<User, Long> repository = // … get access to a bean
Page<User> users = repository.findAll(PageRequest.of(1, 20));
派生1:計數查詢
interface UserRepository extends CrudRepository<User, Long> {
long countByLastname(String lastname);
}
派生2:刪除查詢的接口定義
interface UserRepository extends CrudRepository<User, Long> {
long deleteByLastname(String lastname);
List<User> removeByLastname(String lastname);
}
派生規則:基于方法名解析的概念
JpaRepository支持接口規范方法名查詢。意思是如果在接口中定義的查詢方法符合它的命名規則,就可以不用寫實現。
例如:findByName這個方法表示從數據庫中查詢Name這個屬性等于XXX的所有記錄,類似于SQL語句:select * from xxTable where name=xxx這種形式
這段話有兩個重點:
- 方法名需要在接口中設定
- 必須符合一定的命名規范
方法名構造方法
find+全局修飾+By+實體的屬性名稱+限定詞+連接詞+ ...(其它實體屬性)
+OrderBy+排序屬性+排序方向 例如:findDistinctByFirstNameIgnoreCaseAndLastNameOrderByAgeDesc(
String firstName,String lastName)
{......}
其中:Distinct是全局修飾(非必須),FirstName和LastName是實體的屬性名,And是連接詞,IgnoreCase是限定詞,Age是排序屬性,Desc是排序方向,限定詞和連接詞統稱為“關鍵詞”。
支持的關鍵詞
Keyword | Sample | JPQL snippet |
---|---|---|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals | findByFirstname,findByFirstnameIs,findByFirstnameEquals | … where x.firstname = ?1 |
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
LessThan | findByAgeLessThan | … where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | … where x.age <= ?1 |
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
After | findByStartDateAfter | … where x.startDate > ?1 |
Before | findByStartDateBefore | … where x.startDate < ?1 |
IsNull | findByAgeIsNull | … where x.age is null |
IsNotNull,NotNull | findByAge(Is)NotNull | … where x.age not null |
Like | findByFirstnameLike | … where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended %) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended %) |
Containing | findByFirstnameContainin | … where x.firstname like ?1 (parameter bound wrapped in %) |
OrderBy | findByAgeOrderByLastnameDesc… | where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection<Age> ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection<Age> ages) | … where x.age not in ?1 |
True | findByActiveTrue() | … where x.active = true |
False | findByActiveFalse() | … where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstame) = UPPER(?1) |
@data(省略get和set)
IDE安裝lombok插件同時pom文件添加如下配置
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
實例:
import lombok.Data;
@Data
public class User {
private Integer id;
private String name;
private String password;
}
使用方法:
public static void main(String[] args){
User u=new User ();
u.setId(1);
u.setName("aName");
u.setPassword("aPasswd");
System.out.println(u);
}
JPA接口查詢實例
第一步:對應表和實體類直接的關系
package com.pojo;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;
/*
實體中常用的注解:
@Entity :聲明這個類是一個實體類
@Table:指定映射到數據庫的表
@Id :映射到數據庫表的主鍵屬性,一個實體只能有一個屬性被映射為主鍵
@GeneratedValue:主鍵的生成策略
* */
@Data
@Entity
@Table(name="user")
public class User {
@Id
@GeneratedValue
private Integer id;
private String name;
private String password;
}
第二步:完成接口配置
package com.dao;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface CrudReal extends CrudRepository<User, Integer>{}
第三步:直接用
package com.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.dao.CrudReal;
import com.pojo.User;
@RestController
public class DataCRUD {
@Autowired
private CrudReal crudReal;
@GetMapping("/dataSave")
public String toRedict() {
User u=new User ();
u.setId(1);
u.setName("aName");
u.setPassword("aPasswd");
crudReal.save(u);
crudReal.findAll().iterator().forEachRemaining(a->System.out.println(a.toString()));
return ""+crudReal.count();
}
}
事務
默認情況下,接口上可用的CRUD方法都是事務性的
調整事務配置(定義多個存儲庫調用的事務)
@Service
class UserManagementImpl implements UserManagement {
private final UserRepository userRepository;
private final RoleRepository roleRepository;
@Autowired
public UserManagementImpl(UserRepository userRepository,
RoleRepository roleRepository) {
this.userRepository = userRepository;
this.roleRepository = roleRepository;
}
@Transactional
public void addRoleToAllUsers(String roleName) {
Role role = roleRepository.findByName(roleName);
for (User user : userRepository.findAll()) {
user.addRole(role);
userRepository.save(user);
}
}
MySQL數據庫使用實例
為了測試使用mysql,特意從spring官網下的依賴pom文件,選了jpa和mysql等
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.hjc</groupId>
<artifactId>jpaTest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>jpaTest</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
SQL配置:
spring.datasource.url=jdbc:mysql://localhost/test?useUnicode=true&serverTimezone=UTC
spring.datasource.username=用戶名
spring.datasource.password=用戶密碼
配置了連接的地址和數據庫以及用戶名密碼后
報錯1:時區不對
URL加上serverTimezone=UTC
錯誤2:表找不到
沒辦法,初學者自己建動手建表,但懶人沒辦法,不想動手,那就動腦,用power designer設計表模型,然后自動生成建表的SQL文件,百度power designer教程一堆的,不解釋。
錯誤3,關鍵是table hibernate_sequence doesn't exist
四處百度搜索發現是主鍵自增出了問題。后來找到一個解決辦法,如下:
首先修改注解@GeneratedValue
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
修改主鍵自增策略,隨后在數據庫表的主鍵那里也要
mysql> create table user (
id int(11) not null auto_increment primary key,
name varchar(20),
password varchar(20)
);
加一個auto_increment
來讓其自增,這樣后就可以了。
想著后來可能會連接到其他的表里面,列名不一致何解?于是找了設置對應屬性名和列名的注解
@Column(name="user_name")
private String name;
這樣就可以將屬性name對應到表里面的user_name列了。
要是想看自動執行了哪些SQL語句怎么辦?在配置文件里面添加如下語句即可
spring.jpa.show-sql=true
附加
在父類接口里面找了許久都沒有發現update開頭的方法,百度了其他人的說法才知道原來save開始的既有添加也有修改的含義。后來為了方便執行一些復雜查詢或修改語句找了下面的代碼實現:
@Query(nativeQuery = true, value = "select * from user where name=:name or age=:girls_age ")
List<User> findUsersByAgeAndName(@Param("name") String name, @Param("girls_age") Integer age);
@Transactional
@Modifying
@Query(nativeQuery = true, value = "update user set username=:name where id=:id")
public void updateOneUsers(@Param("id")Long id, @Param("name")String name);
@Modifying
和@Transactional
在修改的時候加,查詢的時候就沒必要加了。表示要修改一個數據且別人不能動(事務)。