当前位置: 首页 > 知识库问答 >
问题:

如何在提交期间捕获SQLExceptions?

高奇
2023-03-14

使用Spring

@Repository
public class UserDAOImpl implements UserDAO {

    @PersistenceContext
    EntityManager em;

    @Override
        public void createUserRole(String role) throws RoleAlreadyExistsException {
            try {
                UserRole userRole = new UserRole(role);
                em.persist(userRole);
            } catch (Exception e) {
                throw new RoleAlreadyExistsException();
            }
        }
}

我的服务:

@Service("userService")
public class UserService 
    @Transactional
        public void createUserRole(String role) throws RoleAlreadyExistsException {
            userDao.createUserRole(role);
        }
}

后来我实现了一些逻辑:

try{
     userService.createUserRole(role.name());
 }  catch (AuthorityEntityAlreadyExistsException e){}

但它没有捕获关于重复密钥的报告的异常:

SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [PRIMARY]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:259)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:225)
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730)

Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
    at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:59)
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:95)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:485)

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'ROLE_ADMIN' for key 'PRIMARY'
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:422)

所以,我的角色并没有被扔出去。我的角色已经不存在了。在服务结束方法的事务提交期间引发异常。如何捕捉异常???或者如何以另一种方式在Spring中实现这种逻辑??

共有3个答案

司空凌
2023-03-14

对DAO或服务或控制器层使用@transactional注释,以便在提交期间捕获任何SQLexception时回滚该方法。

i.e   @transactional
public void method(@param somevalue)
{
  // Database saving or updating function
  }

如果您希望在异常期间显示特定消息

如果您想为特定的ExpException类使用全局处理程序,请使用以下命令

@ExceptionHandler(SQLException.class)      
public String exceptionMessage(){ //return exception message}
赵英范
2023-03-14

EntityManager.persist没有必要执行sql语句:新实体注册在缓存中,并在需要时发送到数据库。

如果数据库检查了您的约束,那么当这个实体被发送到数据库时,您将看到一个错误,在事务提交的最佳情况下:这是您在跟踪中看到的行为。

可以通过调用EntityManager.flush()强制JPA实现将其缓存发送到数据库

public void createUserRole(String role) throws RoleAlreadyExistsException {
   try {
       UserRole userRole = new UserRole(role);
       em.persist(userRole);
       em.flush();
   } catch (Exception e) {
       throw new RoleAlreadyExistsException();
   }
}

然而,调用flush太多可能会导致性能损失,您应该只在必要时调用它。分离DAO和服务可能更简单:在UserService中尝试cach DataIntegrityException,在DAO中不要调用flush

麹凯捷
2023-03-14

1)DAO不应该捕捉异常。让Hibernate或Spring生成的异常被抛出,不要管它。特别是如果您的异常转换非常广泛,并且丢失了信息(丢弃了原始的堆栈跟踪)。

2) 不要依靠违反约束来告诉你有一个预先存在的条目。您可以在告诉Hibernate执行插入之前查询它。只要查询与insert处于同一事务中,并且隔离级别为可重复读取或更好,查询结果就会可靠。

 类似资料:
  • 问题内容: 我只能修改ajax调用中的代码。当我单击名为的表单中的提交时,就会发生ajax调用。 问题答案: 您需要在成功处理程序之前将其停止。因为该函数在您的AJAX调用之后完成执行,所以表单将在进行ajax调用时提交(并且在您的ajax调用结束时为时已晚)。 但是,可以,在函数末尾放置return false。 如果在成功处理程序中确实很重要,则可以同步执行调用。

  • 问题内容: 关于如何使用javascript提交表单似乎有很多信息,但是我正在寻找一种解决方案,以捕获表单提交后在javascript中进行拦截的方法。 的HTML 当用户按下“提交”按钮时,我 不 希望提交表单,而是希望调用JavaScript函数。 一个快速的技巧是在按钮上添加onclick函数,但是我不喜欢这种解决方案…有很多方法可以提交表单…例如,在输入时按回车键,这不能解释。 泰 问题答

  • Spark集群信息: null 我从一个工作人员那里向spark cluster提交了一个jar,我希望从提交中接收driver-Id,这样我就可以在以后的应用程序状态检查中使用该id。问题是我在控制台中没有得到任何输出。我使用端口进行提交,并将部署模式设置为。 通过跑步 在spark日志文件中,我可以看到下面提交的json响应,这正是我想要的: 我假设这不会让冗长的命令发挥作用。如何将其更改为使

  • 问题内容: 我正在尝试在我的一个课程中实现PHP5的类型提示, 正确用法: 产生错误: 可捕获的致命错误:传递给ClassA :: method_a()的参数1必须是ClassB的实例,给定ClassWrong的实例… 是否有可能捕获到该错误(因为它说“可捕获”)?如果是的话,如何? 问题答案: 更新:这不再是php 7中可捕获的致命错误。相反,抛出了“异常”。不是从Exception而是Erro

  • 问题内容: 我几乎从来没有玩过客户端方面的东西,而这个大概简单的任务正在踢我的屁股:) 我有一些链接。OnClick我想阻止默认操作,捕获其href网址,向该url提交ajax GET,并简单地添加结果…但是我什至无法越过起始行:) 播放时间锚点示例: 现在,我已经针对SO上的 类似 请求提出了一些建议,但是这些链接仍然会使浏览器导航到href网址。 即使只是 …链接仍然导航到另一页。 我有点像婴

  • 我正在尝试将一个任务提交给Java的ExecutorService。它要么需要一个Callable,它允许抛出异常,要么需要一个Runnable。我的用例是愚蠢的:我想安排一个抛出异常的任务,但它是一个无效的方法。因此,我不能使用Callable或Runnable,因为方法定义与我的用例不匹配。我还想让我的异常从提交后收到的Future传播。有什么想法吗?