【问题标题】:ConstraintViolationException: Validation failed for classes [....entities.WalletInfo] during persistConstraintViolationException:持久化期间类 [....entities.WalletInfo] 的验证失败
【发布时间】:2017-08-20 04:08:42
【问题描述】:

我使用Spring MVC RESTful 应用程序并在坚持的同时获得ConstraintViolationException。下面提供的错误消息,

Exception in thread " STARTING" javax.validation.ConstraintViolationException: Validation failed for classes [mobi.puut.entities.WalletInfo] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
    ConstraintViolationImpl{interpolatedMessage='may not be null', propertyPath=id, rootBeanClass=class mobi.puut.entities.WalletInfo, messageTemplate='{javax.validation.constraints.NotNull.message}'}
    ConstraintViolationImpl{interpolatedMessage='may not be null', propertyPath=currency, rootBeanClass=class mobi.puut.entities.WalletInfo, messageTemplate='{javax.validation.constraints.NotNull.message}'}
]
    at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:140)
    at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:80)
    at org.hibernate.action.internal.EntityIdentityInsertAction.preInsert(EntityIdentityInsertAction.java:197)
    at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:75)
    at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:626)
    at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:280)
    at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:261)
    at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:306)
    at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:318)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:275)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:182)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:113)
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:189)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:780)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:765)
    at mobi.puut.database.WalletInfoDao.create(WalletInfoDao.java:62)
    at mobi.puut.database.WalletInfoDao$$FastClassBySpringCGLIB$$624213d.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
    at mobi.puut.database.WalletInfoDao$$EnhancerBySpringCGLIB$$a84b41b3.create(<generated>)
    at mobi.puut.services.WalletService.createWalletInfo(WalletService.java:273)
    at mobi.puut.services.WalletService.lambda$generateAddress$0(WalletService.java:97)
    at mobi.puut.controllers.WalletManager$1.lambda$onSetupCompleted$0(WalletManager.java:109)
    at java.lang.Iterable.forEach(Iterable.java:75)
    at java.util.Collections$SynchronizedCollection.forEach(Collections.java:2062)
    at mobi.puut.controllers.WalletManager$1.onSetupCompleted(WalletManager.java:109)
    at org.bitcoinj.kits.WalletAppKit.startUp(WalletAppKit.java:325)
    at com.google.common.util.concurrent.AbstractIdleService$2$1.run(AbstractIdleService.java:54)
    at com.google.common.util.concurrent.Callables$3.run(Callables.java:95)

项目结构如下,

指向下面提供的错误的示例代码,

@Transactional(rollbackFor = Exception.class)
    public WalletInfo create(String name, String address) {

        // create the WalletInfo entity with provided name and address
        WalletInfo walletInfo = new WalletInfo();
        walletInfo.setAddress(address);
        walletInfo.setName(name);

        // persist the created instance into the database
        sessionFactory.getCurrentSession().persist(walletInfo);
        return walletInfo;
    }


protected WalletInfo createWalletInfo(final String walletName, final String address) {
        return walletInfoDao.create(walletName, address);
    }


public synchronized WalletInfo generateAddress(final String walletName, String currencyName) {

        // get the WalletInfo entity from the database with the wallet and the currency name
        WalletInfo walletInfo = walletInfoDao.getWalletInfoWithWalletNameAndCurrency(walletName, currencyName);

        // generate wallet, if the wallet is not
        // generated previously
        if (walletInfo == null) {

            if (genWalletMap.get(walletName) == null) {

                logger.info("Wallet name that we are workign on {}", walletName);

                final WalletManager walletManager = WalletManager.setupWallet(walletName);

                walletManager.addWalletSetupCompletedListener((wallet) -> {

                    Address address = wallet.currentReceiveAddress();
         /*at mobi.puut.services.WalletService.lambda$generateAddress$0(WalletService.java:97) */

                    WalletInfo newWallet = createWalletInfo(walletName, address.toString());

                    walletMangersMap.put(newWallet.getId(), walletManager);
                    genWalletMap.remove(walletName);
                });

                genWalletMap.put(walletName, walletManager);
            }
            return walletInfo;
        }
        return null;
    }



 private void setupWalletKit(final String walletId) {

        File directory = getWalletDirectory(walletId);

        // if the seed is not null, that means we are restoring from the backup
        bitcoin = new WalletAppKit(networkParameters, directory, WALLET_FILE_NAME) {

            @Override
            protected void onSetupCompleted() {

                // Don't make the user wait for confirmations
                // they're sending their own money anyway!!
                bitcoin.wallet().allowSpendingUnconfirmedTransactions();
                Wallet wallet = bitcoin.wallet();

                model.setWallet(wallet);

                /* lambda$onSetupCompleted$0(WalletManager.java:109) */
                setupCompletedListeners.forEach(listener -> listener.onSetupCompleted(wallet));
            }
        };

        // some code 
}

提供的WalletInfo 实体,

@Entity
@Table(name = "wallet_info")
public class WalletInfo {

    @Id
    @Column(name = "id")
//    @NotNull
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotNull
    @Column(name = "name")
    private String name;

    @NotNull
    @Column(name = "address")
    private String address;

    @NotNull
    @Column(name = "currency")
    private String currency;

    public Long getId() {
        return id;
    }

    public WalletInfo(@NotNull String name, @NotNull String address, @NotNull String currency) {
        this.name = name;
        this.address = address;
        this.currency = currency;
    }

    public WalletInfo(@NotNull String name, @NotNull String address) {
        this.name = name;
        this.address = address;
    }

    public WalletInfo() {
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }


    public String getCurrency() {
        return currency;
    }

    public void setCurrency(String currency) {
        this.currency = currency;
    }
}

这里有什么问题以及如何解决?

【问题讨论】:

  • 如果有人提供了要求关闭问题的理由,我可以更新问题。对我来说,这是一个合法的编程问题,需要解决。
  • 消息很清楚。 idcurrency 不应为 NULL。
  • 可能的解决方案(你没有提到你的数据库):确保你的 id 列对于 GenerationType.IDENTITY 自动递增,如果你想将 currency 存储为 NULL 然后设置列可以存储 NULL 数据。
  • 感谢您的评论。现在解决了

标签: java hibernate spring-mvc


【解决方案1】:

评论中提供的解决方案是正确的,我只是想精心编写它以帮助其他人,尤其是新使用Hibernate的人。 WalletInfo 实体与MySQL 中的wallet_info 表匹配,

请注意,每个实体都作为非空 NN 提供,因此需要在数据库中匹配 persisting

修改后的walletInfo实体类,

@Entity
@Table(name = "wallet_info")
public class WalletInfo {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotNull
    @Column(name = "name")
    private String name;

    @NotNull
    @Column(name = "address")
    private String address;

    @NotNull
    @Column(name = "currency")
    private String currency;

    // getters and setters 


   // constructors 

public WalletInfo(@NotNull String name, @NotNull String address, @NotNull String currency) {
        this.name = name;
        this.address = address;
        this.currency = currency;
    }

    public WalletInfo(@NotNull String name, @NotNull String address) {
        this.name = name;
        this.address = address;
    }

    public WalletInfo() {
    }
}

在数据库层,这是我用来persist的方法,

@Transactional(rollbackFor = Exception.class)
public WalletInfo create(String name, String currency, String address) {

    // create the WalletInfo entity with provided name and address
    WalletInfo walletInfo = new WalletInfo();
    walletInfo.setAddress(address);
    walletInfo.setName(name);
    walletInfo.setCurrency(currency);

    // persist the created instance into the database
    sessionFactory.getCurrentSession().persist(walletInfo);
    return walletInfo;
}

我刚刚添加了 currecny 列,因此忘记添加 walletInfo.setCurrency(currency) 行将 currency 更早地设置为 null 并创建错误。我仍然可以将id设为null,因为这不是带有@NotNull注释的构造函数中的元素,并且实体参数定义也没有使用@NotNull进行注释

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

我希望这会帮助一些人。

【讨论】:

    【解决方案2】:

    如果您正在使用 lombok,您可能忘记了实体类上的 @Data-Annotation。

    每个属性都为空的原因,虽然它不应该是空的,但它根本不可能让 spring 将数据写入你的对象,因此会发生异常。没有设置器,没有构造器 => 对象中没有数据,因此内容将始终为空。

    这是一件非常棘手的事情,因为只有在验证数据库条目时才会出现异常,没有 Not-Null-Annotation,它只会将 null 写入您的字段,如果这适用于所有字段...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-14
      • 2011-06-08
      • 2014-04-27
      • 2012-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多