JPA:常见错误解析及其解决方案说明
- 前言
- 一、java.lang.IllegalStateException: Cannot determine target DataSource for lookup key [null] 问题
- 二、javax.persistence.TransactionRequiredException: Executing an update/delete query 问题
- 三、hibernate.exception.GenericJDBCException: could not extract ResultSet 问题
- 四、SQLGrammarException: could not extract ResultSet 问题
- 五、拓展:nativeQuery=true 用法说明
- 总结
前言
很多Java开发者在写后端的时候,经常需要涉及到与数据库的数据交互,JPA就是一种常见的方式。
本文介绍了几种JPA开发中常见的错误及其解决方案,拓展说明了nativeQuery=true 的使用用法。
一、java.lang.IllegalStateException: Cannot determine target DataSource for lookup key [null] 问题
出现该问题的主要原因是:Java执行SQL查询语句时,数据库的指向没有明确。
解决方案:执行SQL前,一定要确保切换到了正确且明确的库,不要把库切错了或者干脆没有明确切换到哪个数据库就直接执行SQL查询语句,这样会很容易出问题。
二、javax.persistence.TransactionRequiredException: Executing an update/delete query 问题
出现该问题的主要原因是:JPA要求:没有事务支持,不能执行增删改操作。
解决方案:在Service层或者Repository层上必须加@Transactional,来代表这是一个事务级别的操作,增删改查除了查都是事务级别的。
代码实例:
推荐:Repository层添加@Transactional
@Transactional
@Modifying
@Query("UPDATE Person p SET p.email = :email WHERE p.id = :id")
void updatePersonEmail(@Param("id") Integer id, @Param("email") String email);
也可以:Service层添加@Transactional
@Transactional
public void UpdateInfo(Integer a,String b){
pubRepository.updateInfo(a,b);
}
三、hibernate.exception.GenericJDBCException: could not extract ResultSet 问题
出错原因:JPA要求:在@Query注解中编写SQL实现 Delete 和 Update 操作的时候必须加上 @Modifying 注解,以通知 Spring Data 这是一个 Delete 或 Update 操作
解决方案:
@Transactional
@Modifying
@Query("UPDATE Person p SET p.email = :email WHERE p.id = :id")
void updatePersonEmail(@Param("id") Integer id, @Param("email") String email);
四、SQLGrammarException: could not extract ResultSet 问题
这个问题和第四个问题有点相似,都是could not extract ResultSet,但是原理不太一样。
出错原因:无法提取ResultSet,也就是说SQL返回的结果和实体类不匹配。
-
解决方案
- (1) 检查 SQL 的查询内容和数据库列名是否匹配
- (2) hibernate呢必须给实体类指定主键,需要在实体类里面加入注解。其中,@Id用来表示主键,@Basic用来表示非主键,@Column用来表示列名。
- (3)JPA的 save 方法,在保存后会返回一个实体,因为没有主键的原因,所以就导致了报错。
代码示例如下:
@Entity
@Table(name = "PUB_BMXX")
@IdClass(BmxxInfoEntityPK.class) //标识实体类的主键说明类
public class BmxxInfoEntity {
private Integer xh;
private String bmmc;
@Id
@Column(name = "XH")
public Integer getXh() {
return xh;
}
public void setXh(Integer xh) {
this.xh= xh;
}
@Basic
@Column(name = "BMMC")
public String getBmmc() {
return bmmc;
}
public void setBmmc(String bmmc) {
this.bmmc= bmmc;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BmxxInfoEntity that = (BmxxInfoEntity) o;
return Objects.equals(xh, that.xh) &&
Objects.equals(bmmc, that.bmmc);
}
@Override
public int hashCode() {
return Objects.hash(xh, bmmc);
}
}
五、拓展:nativeQuery=true 用法说明
解释:nativeQuery = true时,是可以执行原生sql语句,原生sql意思是这段sql拷贝到数据库中,然后把参数值给一下就能运行了(推荐使用!更符合常规使用习惯,和数据库中写的SQL相同)
示例如下:
@Query("select * from pub_ryxx where rymc=?1",nativeQuery=true)
Ryxx findByRymc(@Param("RYMC") String rymc);
其中,pub_ryxx 是数据库中的表名,rymc 是 pub_ryxx 表中的一个字段名称。
nativeQuery = false时,就不支持原生SQL了。
示例如下:
@Query("select rybh from Ryxx where rymc=?1",nativeQuery=false)
String findByRymc(@Param("RYMC") String rymc);
其中,Ryxx 是实体类的类名,rybh、rymc 都是是实体类中的一个字段名。
这种写法不太符合常规使用习惯,不推荐使用,但是两种方式的效果是一样的。
总结
本文介绍了几种JPA开发中常见的错误及其解决方案,拓展说明了nativeQuery=true 的使用用法。
希望对大家有用!