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
在修改的时候加,查询的时候就没必要加了。表示要修改一个数据且别人不能动(事务)。
网友评论