如何使用 JPA Query 将数据插入数据库?

Posted

技术标签:

【中文标题】如何使用 JPA Query 将数据插入数据库?【英文标题】:How to use JPA Query to insert data into db? 【发布时间】:2017-08-02 01:09:54 【问题描述】:

我的准备语句有问题,但我不知道错误在哪里。我正在尝试将 URI 链接插入到数据库中。

 @Repository
 public interface LoggerDao extends CrudRepository<Logger, Long> 
 @Query("select t from Logger t where t.user.id=?#principal.id")
 List<Logger> findAll();

@Modifying
@Query(value = "insert into Logger t (t.redirect, t.user.id) VALUES (:insertLink,?#principal.id)", nativeQuery = true)
@Transactional
void logURI(@Param("insertLink") String insertLink);

错误

    2017-03-11 19:52:59.157  WARN 65154 --- [nio-8080-exec-8] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 42001, SQLState: 42001
2017-03-11 19:52:59.157 ERROR 65154 --- [nio-8080-exec-8] o.h.engine.jdbc.spi.SqlExceptionHelper   : Syntax error in SQL statement "INSERT INTO LOGGER T[*] (T.REDIRECT, T.USER.ID) VALUES (?,?) "; expected "., (, DIRECT, SORTED, DEFAULT, VALUES, SET, (, SELECT, FROM"; SQL statement:
insert into Logger t (t.redirect, t.user.id) VALUES (?,?) [42001-190]
2017-03-11 19:52:59.181 ERROR 65154 --- [nio-8080-exec-8] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare statement; SQL [insert into Logger t (t.redirect, t.user.id) VALUES (?,?)]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement] with root cause

org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "INSERT INTO LOGGER T[*] (T.REDIRECT, T.USER.ID) VALUES (?,?) "; expected "., (, DIRECT, SORTED, DEFAULT, VALUES, SET, (, SELECT, FROM"; SQL statement:
insert into Logger t (t.redirect, t.user.id) VALUES (?,?) [42001-190]
    at org.h2.engine.SessionRemote.done(SessionRemote.java:624) ~[h2-1.4.190.jar:1.4.190]
    at org.h2.command.CommandRemote.prepare(CommandRemote.java:68) ~[h2-1.4.190.jar:1.4.190]
    at org.h2.command.CommandRemote.<init>(CommandRemote.java:45) ~[h2-1.4.190.jar:1.4.190]
    at org.h2.engine.SessionRemote.prepareCommand(SessionRemote.java:494) ~[h2-1.4.190.jar:1.4.190]
    at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1188) ~[h2-1.4.190.jar:1.4.190]
    at org.h2.jdbc.JdbcPreparedStatement.<init>(JdbcPreparedStatement.java:72) ~[h2-1.4.190.jar:1.4.190]
    at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:276) ~[h2-1.4.190.jar:1.4.190]
    at org.apache.tomcat

【问题讨论】:

您不能将 WHERE 子句直接与 INSERT 语句一起使用。你想达到什么目的?对我来说,这种说法没有意义。 看来你应该使用UPDATE 而不是INSERT @JackFlamp 我有一个更新语句,但由于该字段中没有任何内容可以更新,所以它不会执行。 @VimalKumar 我正在尝试将 URI 名称保存到数据库中 @ARTHURDECKER 由于INSERT INTO 将新记录(行)添加到表中,因此使用WHERE 子句没有意义。要么你想添加一条新记录,要么更新一条。 【参考方案1】:

我设法解决了这个问题。我在参数中添加了一个 id,以便我可以在控制器中使用 Principal 传递用户的 id。

@Repository
public interface LoggerDao extends CrudRepository<Logger, Long> 
    @Query("select t from Logger t where t.user.id=?#principal.id")
    List<Logger> findAll();

    @Modifying
    @Query(value = "insert into Logger (redirect,user_id) VALUES (:insertLink,:id)", nativeQuery = true)
    @Transactional
    void logURI(@Param("insertLink") String insertLink, @Param("id") Long id);

【讨论】:

如果我们用@query tag 编写整个查询,那么为什么要使用JPA?普通的 jdbc 也会这样做。您使用 spring jpa 而不是普通的 jdbc 或 hibernate 有什么具体原因吗? @Stunner JPA 不支持插入语句:baeldung.com/spring-data-jpa-query#3-inserts。如果您必须在本机 SQL 中编写插入语句,那么仅使用计划 JDBC 是公平的。但是,IMO 的缺点是它会产生一个单独的 JDBC 类,因此您会将数据库操作拆分为 CrudRepsitory 接口和 JDBC DAO 类,这会使 IMO 对代码库上的开发人员感到困惑。 比@SqlInsert imo 干净得多。【参考方案2】:

有一种方法可以使用 obj(非本机)查询(使用 @Query 和 @Modifying)进行插入,但这取决于您使用的数据库。下面在 Oracle 中为我工作(使用双表):

@Repository
public interface DualRepository extends JpaRepository<Dual,Long> 
    @Modifying
    @Query("insert into Person (id,name,age) select :id,:name,:age from Dual")
    public int modifyingQueryInsertPerson(@Param("id")Long id, @Param("name")String name, @Param("age")Integer age);

这是一个链接,它在底部显示哪个 db 支持不带 from 子句的 select stmts:http://modern-sql.com/use-case/select-without-from

【讨论】:

如果启用了nativeQuery,则不能使用插入语句(默认启用)

以上是关于如何使用 JPA Query 将数据插入数据库?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 JPA 中进行 BATCH 插入?

如何使用类中的 setters 方法将数据插入 JPA 实体表?

如何使用Spring数据jpa @Query注释直接获取学生列表

如果属性对 JPA 无效,我如何在数据库中插入默认值

spring-data-jpa 使用 @Query 和 @Modifying 插入而不使用 nativeQuery 或 save() 或 saveAndFlush()

Jpa多对多如何仅将数据插入2个表