快速上手
- 在 pom.xml 文件中添加jpa依赖
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 集成jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
- application.yml 里面配置jdbc连接和jpa
#配置jdbc
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.0.223:3306/warehouse?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&characterSetResults=utf8
username: root
password: root
dbcp2:
min-idle: 5 #数据库连接池最小的连接数
initial-size: 5 #初始化连接数
max-total: 10 #最大连接数
max-wait-millis: 1000 #等待连接获取的最大超时时间
jpa:
hibernate:
ddl-auto: update # 第一次建表create 后面用update,要不然每次重启都会新建表
show-sql: true #控制台打印SQL日志
解 释
hibernate.ddl-auto 参数有四个值:
create:每次加载 hibernate 时都会删除上一次的生成的表,然后根据你的 model
类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。
create-drop :每次加载 hibernate 时根据 model 类生成表,但是 sessionFactory 一关闭,表就自动删除。
update:最常用的属性,第一次加载 hibernate 时根据 model 类会自动建立起表的结构(前提是先建立好数据库),以后加载hibernate 时根据 model类自动更新表结构,即使表结构改变了,但表中的行仍然存在,不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等应用第一次运行起来后才会。
validate :每次加载 hibernate 时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。
- 在domain包下建立一个CoinUser实体类
@Entity(name = "coin_user")
public class CoinUser implements Serializable {
@Id
@GeneratedValue
private Long id;
@Column(name = "login_name", nullable = false, unique = true)
private String loginName;
@Column(nullable = false)
private String password;
@Column(nullable = false, unique = true)
private String email;
@Column(nullable = false, unique = true)
private String mobile;
此处省略set、get、构造方法...
}
注 解 解 释
-
@Entity:表明该类(CoinUser )为实体类,默认对应数据库表名为 coin_user
写成:@Entity(name = “coin_user”)
或者:@Entity
@Table(name = “coin_user”) -
@Id:声明一个实体类的属性映射为数据库的主键列
-
@GeneratedValue:用于标注主键生成的策略,mysql默认对应 auto increment(主键自增)
-
@Column:
name = “login_name”:指这个字段与用户的login_name进行映射(实体类属性与数据库字段不一致时)
nullable = false:指这个字段的值不能为null;
unique = true:指这个字段的值在这张表里不能重复,所有记录值都要唯一
注 解 图 详 解
- 在repository包下建立Dao接口,名为CoinUserRepository,继承JpaRepository接口,JpaRepository接口需要传递两个参数,第一个为实体类对象,第二个为主键类型。
public interface CoinUserRepository extends JpaRepository<CoinUser, Long> {
}
到此为止基本环境已经搭建好,接下直接上手体验吧!
基本查询
基本查询分为两种,一种是Spring Data默认已经实现的,另一种是根据查询方法自动解析SQL。
继承 JpaRepository 后默认生成的增、删、改、查方法(根据方法名即可见名知意):
List<T> findAll();
List<T> findAll(Sort var1);
List<T> findAllById(Iterable<ID> var1);
void delete(T var1);
void deleteAll();
<S extends T> S save(S var1);
......
在controller包建立CoinController,引入Dao层接口,进行测试
@RestController
@RequestMapping(value = "/coin")
public class CoinController {
@Autowired
private CoinUserRepository coinUserRepository;
/**
* 查询所有用户信息
* @author 药岩
* @date 2020/1/19
* @param * @param
* @return java.util.List<com.coin.coindevin.domain.CoinUser> 用户集合
*/
@RequestMapping(value = "/findUserList")
@ResponseBody
public List<CoinUser> findUserList(){
return coinUserRepository.findAll();
}
}
浏览器访问:http://localhost:8099/coin/findUserList
效果如下:
这里返回的JSON以树形进行展示是因为我这边安装了谷歌插件JSON-handle
自定义简单查询
- 自定义简单查询就是根据方法名自动生成SQL,主要语法:
findXXBy、readAXXBy、queryXXBy、countXXBy、getXXBy 后面跟属性名称:
例如:
//根据登入名查询用户信息
CoinUser findByUserName(String LoginName);
- 当加上And或者Or时:
//根据登入名或者id查询用户信息
CoinUser findByUserNameOrId(String LoginName, int id);
- 当加上LIKE、Containing、IgnoreCase、OrderBy时:
此处为测试方便,不写service层接口,直接controller调用dao,实际开发中切不可这样子操作。
Dao层
public interface CoinUserRepository extends JpaRepository<CoinUser, Integer> {
//根据登入名模糊查询用户集合信息(底层没有实现模糊查询,参数需要添加'% %')
List<CoinUser> findByLoginNameLike(String name);
//根据邮箱模糊查询用户集合信息(底层已经实现模糊查询,不需要添加'% %')
List<CoinUser> findByEmailContaining(String email);
//根据邮箱搜索用户集合信息(不区分邮箱大小写名)
List<CoinUser> findByEmailIgnoreCase(String email);
//根据密码查询用户信息集合并按Id降序
List<CoinUser> findByPasswordOrderByIdAsc(String password);
}
controller层
@RestController
@RequestMapping(value = "/coin")
public class CoinController {
@Autowired
private CoinUserRepository coinUserRepository;
/**
* 根据登入名模糊查询用户集合信息(底层没有实现模糊查询,参数需要添加'% %')
* @author 药岩
* @date 2020/1/19
*/
@RequestMapping(value = "/findUserLike")
@ResponseBody
public List<CoinUser> findUserLike(String loginName){
return coinUserRepository.findByLoginNameLike("%" + loginName + "%");
}
/**
* 根据邮箱模糊查询用户集合信息(底层已经实现模糊查询,不需要添加'% %')
* @author 药岩
* @date 2020/1/19
*/
@RequestMapping(value = "/findUserContaining")
@ResponseBody
public List<CoinUser> findUserContaining(String email){
return coinUserRepository.findByEmailContaining(email);
}
/**
* 根据邮箱搜索用户集合信息(不区分邮箱大小写名)
* @author 药岩
* @date 2020/1/19
*/
@RequestMapping(value = "/findUserIgnoreCase")
@ResponseBody
public List<CoinUser> findUserIgnoreCase(String email){
return coinUserRepository.findByEmailIgnoreCase(email);
}
/**
* 根据密码查询用户信息集合并按Id升序
* @author 药岩
* @date 2020/1/19
*/
@RequestMapping(value = "/findUserOrderBy")
@ResponseBody
public List<CoinUser> findUserOrderBy(String password){
return coinUserRepository.findByPasswordOrderByIdAsc(password);
}
}
关键字的使用和生产SQL:
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 | 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 | findByFirstnameContaining | … 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 ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection age) | … 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) |
限制查询
在有些情况下我们可能只需要通过排序、分页查询特定的前N个元素。
Dao持久层接口
public interface CoinUserRepository extends JpaRepository<CoinUser, Long> {
/**
* 通过Id升序查询前一个用户信息
* @author 药岩
* @date 2020/1/19
*/
CoinUser findTopByOrderByIdAsc();
/**
* 通过Id升序查询第一个用户信息
* @author 药岩
* @date 2020/1/19
*/
CoinUser findFirstByOrderByIdAsc();
/**
* 通过分页控制查询前五个用户信息
* @author 药岩
* @date 2020/1/19
*/
Page<CoinUser> findAll( Pageable pageable);
/**
* 通过登入名查询并通过id升序,查询前五条用户信息
* @author 药岩
* @date 2020/1/20
*/
List<CoinUser> findFirst5ByLoginName(String LoginName, Sort sort);
}
Controller控制层接口编写
@RestController
@RequestMapping(value = "/coin")
public class CoinController {
@Autowired
private CoinUserRepository coinUserRepository;
/**
* 通过Id升序查询第一个用户信息
* @author 药岩
* @date 2020/1/19
*/
@RequestMapping(value = "/findUserTop")
@ResponseBody
public CoinUser findUserTop(){
return coinUserRepository.findTopByOrderByIdAsc();
}
/**
* 通过Id升序查询第一个用户信息
* @author 药岩
* @date 2020/1/19
*/
@RequestMapping(value = "/findUserFirst")
@ResponseBody
public CoinUser findUserFirst(){
return coinUserRepository.findFirstByOrderByIdAsc();
}
/**
* 通过分页控制查询前五个用户信息
* @author 药岩
* @date 2020/1/19
*/
@RequestMapping(value = "/findUserPage")
@ResponseBody
public Page<CoinUser> findUserPage(String loginName){
PageRequest pageable = PageRequest.of(0, 5);
return coinUserRepository.findAll(pageable);
}
/**
* 通过登入名查询并通过id升序,查询前五条用户信息
* @author 药岩
* @date 2020/1/19
*/
@RequestMapping(value = "/findUserSort")
@ResponseBody
public List<CoinUser> findUserSort(String LoginName){
//Sort.Direction.ASC:升序
//id:通过id升序
Sort sort = Sort.by(Sort.Direction.ASC, "id");
return coinUserRepository.findFirst5ByLoginName(LoginName, sort);
}
}
自定义SQL查询
使用 Spring Data 大部分的 SQL 都可以根据方法名定义的方式来实现,但是由于某些原因我们想使用自定义的 SQL 来查询,Spring Data 也可以完美支持;在 SQL 的查询方法上面使用 @Query 注解,如涉及到删除和修改需要加上 @Modifying。也可以根据需要添加 @Transactional 对事物的支持,查询超时的设置等。
@Transactional(timeout = 10)
@Modifying
@Query("update User set userName = ?1 where id = ?2")
int modifyById(String userName, Long id);
@Transactional
@Modifying
@Query("delete from User where id = ?1")
void deleteById(Long id);
@Query("select u from User u where u.email = ?1")
User findByEmail(String email);
多表查询
在平常项目中可能会有多表进行关联查询出结果集,Spring Data JPA 中有两种实现方式,第一种是利用 Hibernate 的级联查询来实现,第二种是创建一个结果集的接口来接收连表查询后的结果。
多数据源配置
由于时间原因,还未更新完,敬请期待!