一、简介:
Java Persistence API:用于对象持久化的 API。Java EE 5.0 平台标准的 ORM 规范,使得应用程序以统一的方式访问持久层。JPA 是 hibernate 的一个抽象,将Java应用与数据库解耦,开发者不用关心Sql的编写,和底层数据库的种类。
二、示例:
-
引入相应依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
-
数据源相关配置
spring.datasource.url = jdbc:mysql://106.13.181.6:3306/FA?useUnicode=true&characterEncoding=UTF-8 spring.datasource.username = root spring.datasource.password= Wanghaiyun@12345 spring.datasource.driver-class-name = com.mysql.jdbc.Driver spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl spring.jpa.show-sql = true
-
Controller层编写
package com.study.demo.controller; import com.google.gson.Gson; import com.study.demo.entity.UserInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import com.study.demo.service.UserInfoService; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.UUID; @Controller @RequestMapping("/demo") public class UserInfoController { private static Logger LOGGER = LoggerFactory.getLogger(UserInfoController.class); @Autowired private UserInfoService userInfoService; private static Gson gson = new Gson(); @ResponseBody @RequestMapping("/queryUser_{userId}.htm") public String queryUserInfoByUserId (@PathVariable String userId) { return gson.toJson(userInfoService.selectByPrimaryKey(userId)); } @ResponseBody @RequestMapping(value = "/saveUser.htm", method = RequestMethod.POST) public String saveUserInfo (UserInfo userInfo) { UUID uuid = UUID.randomUUID(); userInfo.setId(uuid.toString()); try { userInfoService.persistUserInfo(userInfo); } catch (Exception e){ LOGGER.error("UserInfoController.saveUserInfo Error. userInfo:{}, e:{}", gson.toJson(userInfo), e); return "Error"; } return "OK"; } @ResponseBody @RequestMapping(value = "/queryAllByCreateTime.htm", method = RequestMethod.POST) public String queryAllByCreateTime (String createTime) { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try { Date date = format.parse(createTime); List<UserInfo> infoList = userInfoService.queryAllByCreateTimeAfter(date); if (!CollectionUtils.isEmpty(infoList)) { return gson.toJson(infoList); } } catch (Exception e) { LOGGER.error("UserInfoController.queryAllByCreateTime Error. createTime:{}, e:{}", createTime, e); } return null; } }
-
Dao层编写
package com.study.demo.dao; import com.study.demo.entity.UserInfo; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import java.util.Date; import java.util.List; @Repository public interface UserInfoDao extends JpaRepository<UserInfo, String>{ UserInfo queryUserInfoById(String id); List<UserInfo> queryAllByCreateTimeAfter(Date createTime); }
-
Entity层编写
package com.study.demo.entity; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; import java.io.Serializable; import java.util.Date; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; @Data @Entity @Table(name = "USER_INFO") public class UserInfo implements Serializable { private static final long serialVersionUID = 860529229491709995L; @Id @Column(name = "ID") private String id; @Column(name = "NAME") private String name; @Column(name = "SEX") private String sex; @Column(name = "BIRTHDAY") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date birthday; @Column(name = "AGE") private Integer age; @Column(name = "ADDRESS") private String address; @Column(name = "CREATE_TIME") private Date createTime = new Date(); }
三、用法说明
简单的CURD在JpaRepository已经提供了,对于复杂的查询可以通过关键字拼接方法名的方式来实现。
例如上述例子中,查询所有在某时间之后创建的用户信息,通过After关键字,表示在xx日期之后,入参为Date格式,CreateTime为Entity对象的属性,通过驼峰方式拼接。
相关的关键字还有:(摘自:https://blog.csdn.net/lionel_zsj/article/details/98937678)
关键字 | 简单示例 | JPQL片段示例 |
---|---|---|
AND | findByLastNameAndFirstName | WHERE Entity.lastName = ?1 AND Entity.firstName = ?2 |
IsNull | findByAddressIsNull | WHERE Entity.address is NULL |
IsNotNull | readByAddressIsNotNull | WHERE Entity.address NOT NULL |
NotNull | readByAddressNotNull | WHERE Entity.address NOT NULL |
OR | readByLastNameOrFirstName | WHERE Entity.lastName = ?1 OR Entity.firstName = ?2 |
Between | getByStartDateBetween | WHERE Entity.startDate BETWEEN ?1 AND ?2 |
LessThan | findByAgeLessThan | WHERE Entity.age < ?1 |
GreaterThan | readByAgeGreaterThan | WHERE Entity.age > ?1 |
After只作用在时间 | findByStartDateAfter | WHERE Entity.startDate > ?1 |
Before只作用在时间 | findByStartDateBefore | WHERE Entity.startDate < ?1 |
LessThanEqual | findByAgeLessThenEqual | WHERE Entity.age <= ?1 |
GreaterThanEqual | readByAgeGreaterThenEqual | WHERE Entity.age >= ?1 |
Is | findByLastNameIs | WHERE Entity.lastName = ?1 |
Equal | getByFirstNameEqual | WHERE Entity.firstName = ?1 |
Like | findByNameLike | WHERE Entity.name LIKE ? 不包括’%'符号 |
Not Like | findByNameNotLike | WHERE Entity.name not like ?1 不包括’%'符号 |
StartingWith | readByNameStartingWith | WHERE Entity.name like ‘?1%’条件以’%'符号结尾 |
EndingWith | readByName EndingWith | WHERE Entity.name like ‘%?1’条件以’%'符号开头 |
Containing | getByNameContaining | WHERE Entity.name like ‘%?1%’ 包含’%'符号 |
OrderBy | findByAgeOrderByAddressDesc | WHERE Entity.age = ? Order By Entity.address DESC |
Not | readByAgeNot | WHERE Entity.age <> ?1 不等于 |
In | findByNameIn(Collection name) | WHERE Entity.name IN (?1 ,?2, ?3) |
NotIn | getByNameNotIn(Collection name) | WHERE Entity.name NOT IN (?1 ,?2, ?3) |
True | readByFloagTrue() | WHERE Entity.floag = true |
False | readByFloagFalse() | WHERE Entity.floag = false |
IgnoreCase | findByNameIgnoreCase | WHERE UPPER(Entity.Name) = UPPER(?1) |
一些复杂查询可以使Dao层接口继承JpaSpecificationExecutor接口,使用Specification对象和Pageable对象分页查询。也可以使用ExampleMatcher对象。如:
package com.study.demo.dao;
import com.study.demo.entity.UserInfo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
import java.util.Date;
import java.util.List;
@Repository
public interface UserInfoDao extends JpaRepository<UserInfo, String>, JpaSpecificationExecutor<UserInfo> {
UserInfo queryUserInfoById(String id);
List<UserInfo> queryAllByCreateTimeAfter(Date createTime);
}
Service层实现方法:
package com.study.demo.service.Impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import com.study.demo.dao.UserInfoDao;
import com.study.demo.entity.UserInfo;
import com.study.demo.service.UserInfoService;
import javax.persistence.criteria.Predicate;
import java.util.Date;
import java.util.List;
@Service
public class UserInfoServiceImpl implements UserInfoService {
@Autowired
private UserInfoDao userInfoDao;
@Override
public UserInfo selectByPrimaryKey(String id) {
return userInfoDao.queryUserInfoById(id);
}
@Override
public void persistUserInfo(UserInfo userInfo) {
userInfoDao.save(userInfo);
}
@Override
public List<UserInfo> queryAllByCreateTimeAfter(Date createTime) {
return userInfoDao.queryAllByCreateTimeAfter(createTime);
}
@Override
public List<UserInfo> queryAllBySexAndCreateTime(String sex, Date createTime, int page, int size){
Specification<UserInfo> specification = (Specification<UserInfo>) (root, query, builder) -> {
Predicate first = builder.equal(root.get("sex"), sex);
Predicate second = builder.greaterThan(root.get("createTime"), createTime);
return builder.and(first, second);
};
Pageable pageable = PageRequest.of(page-1, size);
return userInfoDao.findAll(specification, pageable).getContent();
}
}
查询SQL如下:
Hibernate: select userinfo0_.ID as ID1_0_, userinfo0_.ADDRESS as ADDRESS2_0_, userinfo0_.AGE
as AGE3_0_, userinfo0_.BIRTHDAY as BIRTHDAY4_0_, userinfo0_.CREATE_TIME as CREATE_T5_0_,
userinfo0_.NAME as NAME6_0_, userinfo0_.SEX as SEX7_0_ from USER_INFO userinfo0_ where
userinfo0_.SEX=? and userinfo0_.CREATE_TIME>? limit ?, ?
四、问题总结
1、java.sql.SQLSyntaxErrorException: Table ‘FA.user_info’ doesn’t exist
参考:https://blog.csdn.net/jiangyu1013/article/details/80395579
原因:由于mysql区分表名大小写导致,一种方案是配置数据库,一种是配置项目
解决方案一:
添加配置:
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
解决方案二:
原因:
MySQL对lower_case_table_names使用区分大小写的表名比较设置 (可能值为’0’)。但是,FishEye在表名 FE-4276中不一致-数据库表OPEN的大小写不一致。您可以使用以下查询确认设置:
show variables like ‘lower_case_table_names’;
解决:
在MySQL中设置 lower_case_table_names的值为’0’
重新启动MySQL和FishEye / Crucible。