Java 如何在hibernate中保留原子整数而不是整数?

Java 如何在hibernate中保留原子整数而不是整数?,java,multithreading,hibernate,jpa,atomicinteger,Java,Multithreading,Hibernate,Jpa,Atomicinteger,我尝试使用hibernatejava框架持久化具有AtomicInteger变量而不是Integer的对象(保存对象后,我需要在线程安全方案中使用该对象),但当我尝试保存对象时,java抛出: java.lang.ClassCastException: java.util.concurrent.atomic.AtomicInteger cannot be cast to java.lang.Integer 有没有办法将AtomicInteger映射到integer?有一个对象的示例: publ

我尝试使用hibernatejava框架持久化具有AtomicInteger变量而不是Integer的对象(保存对象后,我需要在线程安全方案中使用该对象),但当我尝试保存对象时,java抛出:

java.lang.ClassCastException: java.util.concurrent.atomic.AtomicInteger cannot be cast to java.lang.Integer
有没有办法将AtomicInteger映射到integer?有一个对象的示例:

public class Statistics implements java.io.Serializable {
  private AtomicInteger id;
  private AtomicInteger totalErrors;

  public Statistics() {
  }


  public AtomicInteger getTotalErrors() {
    return this.totalErrors;
  }

  public void seTotalErrors(AtomicInteger totalErrors) {
    this.totalErrors= totalErrors;
  }
}
以及相应的POJO xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
   <class name="Statistics" table="statistics" catalog="example" optimistic-lock="version">
      <id name="id" type="java.lang.Integer">
         <column name="id" />
         <generator class="identity" />
      </id>
      <property name="totalErrors" type="java.lang.Integer">
         <column name="total_errors" />
      </property>
   </class>
</hibernate-mapping>

还有hibernate版本:

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.2.10.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-hikaricp</artifactId>
        <version>5.2.10.Final</version>
    </dependency>

org.hibernate
冬眠核心
5.2.10.最终版本
org.hibernate
冬眠
5.2.10.最终版本

一种方法是编写一个JPA2.1,将整数转换为原子整数,如下所示

@Converter
public class AtomicIntConverter implements AttributeConverter<AtomicInteger, Integer> {


 @Override
 public Integer convertToDatabaseColumn(AtomicInteger attribute) {
  return attribute.get();
 }

 @Override
 public AtomicInteger convertToEntityAttribute(Integer dbData) {
  return new AtomicInteger(dbData);
 }

}
你可以在

但在使用hibernate映射文件时,请确保将转换器类的FQN设置为字段类型,而不是使用
@Converter
注释

<property name="totalErrors" type="fully.qualified.name.of.AtomicIntConverter">
     <column name="total_errors" />
 </property>

一种方法是编写一个JPA2.1,将整数转换为原子整数,如下所示

@Converter
public class AtomicIntConverter implements AttributeConverter<AtomicInteger, Integer> {


 @Override
 public Integer convertToDatabaseColumn(AtomicInteger attribute) {
  return attribute.get();
 }

 @Override
 public AtomicInteger convertToEntityAttribute(Integer dbData) {
  return new AtomicInteger(dbData);
 }

}
你可以在

但在使用hibernate映射文件时,请确保将转换器类的FQN设置为字段类型,而不是使用
@Converter
注释

<property name="totalErrors" type="fully.qualified.name.of.AtomicIntConverter">
     <column name="total_errors" />
 </property>

最后,更好的解决方案(因为是更标准的hibernate转换器)是创建hibernate用户类型类。我不知道原因是什么,因为AttributeConverter不工作(因为它在hibernate文档中)

这在我使用Hibernate 5.2的情况下有效。 创建实现hibernate用户类型的AtomicIntegerType:

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.usertype.UserType;

public class AtomicIntegerType implements UserType {

    private static final Logger logger = Logger.getLogger("AtomicInteger");

    /**
     * Returns the object from the 2 level cache
     */
    @Override
    public Object assemble(final Serializable cached, final Object owner)
            throws HibernateException {
        //would work as the AtomicInteger.class is Serializable, 
        //and stored in cache as it is - see disassemble
        return cached;
    }

    /**
     * Used to create Snapshots of the object
     */
    @Override
    public Object deepCopy(Object value) throws HibernateException {
        //return value; -> if AtomicInteger.class was immutable we could return the object as it is
        final AtomicInteger recievedParam = (AtomicInteger) value;
        final AtomicInteger atomicInteger = new AtomicInteger(recievedParam.get());
        return atomicInteger;
    }

    /**
     * method called when Hibernate puts the data in a second level cache. The
     * data is stored in a serializable form
     */
    @Override
    public Serializable disassemble(final Object value) throws HibernateException {
        //For this purpose the AtomicInteger.class must implement serializable
        return (Serializable) value;
    }

    /**
     * Used while dirty checking - control passed on to the
     * {@link AtomicInteger}
     */
    @Override
    public boolean equals(final Object o1, final Object o2) throws HibernateException {
        boolean isEqual = false;
        if (o1 == o2) {
            isEqual = true;
        }
        if (null == o1 || null == o2) {
            isEqual = false;
        } else {
            isEqual = o1.equals(o2);
        }
        return isEqual;
        //for this to work correctly the equals() 
        //method must be implemented correctly by AtomicInteger class
    }

    @Override
    public int hashCode(final Object value) throws HibernateException {
        return value.hashCode();
        //for this to work correctly the hashCode() 
        //method must be implemented correctly by AtomicInteger class

    }

    /**
     * Helps hibernate apply certain optimizations for immutable objects
     */
    @Override
    public boolean isMutable() {
        return true; //The audit fields can be modified
    }

    /**
     * This method retrieves the property value from the JDBC resultSet
     */
    @Override
    public Object nullSafeGet(ResultSet resultSet, String[] names, SharedSessionContractImplementor ssci, Object owner) throws HibernateException, SQLException {
        //owner here is class from where the call to retrieve data was made.
        //In this case the Test class
        AtomicInteger atomicInteger = null;
        if (!resultSet.wasNull()) {
            atomicInteger = new AtomicInteger(resultSet.getInt(names[0]));            
        }
        return atomicInteger;
    }

    /**
     * The method writes the property value to the JDBC prepared Statement
     *
     */
    @Override
    public void nullSafeSet(final PreparedStatement statement,
            final Object value, final int index, SharedSessionContractImplementor ssci) throws HibernateException,
            SQLException {
        if (null == value) {
            statement.setNull(index, java.sql.Types.INTEGER);
        } else {
            AtomicInteger atomicInteger = (AtomicInteger) value;
            if (null != atomicInteger) {
                statement.setInt(index , atomicInteger.get());
            } else {
                statement.setNull(index, java.sql.Types.INTEGER);
            }

        }
    }

    /**
     * Method used by Hibernate to handle merging of detached object.
     */
    @Override
    public Object replace(final Object original, final Object target,
            final Object owner)
            throws HibernateException {
        //return original; // if immutable use this
        //For mutable types at bare minimum return a deep copy of first argument
        return this.deepCopy(original);

    }

    /**
     * Method tells Hibernate which Java class is mapped to this Hibernate Type
     */
    @SuppressWarnings("rawtypes")
    @Override
    public Class returnedClass() {
        return AtomicInteger.class;
    }

    /**
     * Method tells Hibernate what SQL columns to use for DDL schema generation.
     * using the Hibernate Types leaves Hibernate free to choose actual SQl
     * types based on database dialect. (Alternatively SQL types can also be
     * used directly)
     */
    @Override
    public int[] sqlTypes() {
        //createdBy, createdDate,modifiedBy,modifiedDate
        return new int[]{java.sql.Types.INTEGER};
    }

}
在hibernate映射文件中,将Integer更改为AtomicIntegerType,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- Generated 12-sep-2017 13:14:50 by Hibernate Tools 4.3.1 -->
<hibernate-mapping>
   <class name="classs.location.Statistics" table="statistics" catalog="CATALOG" optimistic-lock="version">
      <id name="id" type="java.lang.Integer">
         <column name="id" />
         <generator class="identity" />
      </id>
      <property name="totalErrors" type="class.location.AtomicIntegerType">
         <column name="total_errors" />
      </property>
   </class>
</hibernate-mapping>

最后,更好的解决方案(因为是更标准的hibernate转换器)是创建hibernate用户类型类。我不知道原因是什么,因为AttributeConverter不工作(因为它在hibernate文档中)

这在我使用Hibernate 5.2的情况下有效。 创建实现hibernate用户类型的AtomicIntegerType:

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.usertype.UserType;

public class AtomicIntegerType implements UserType {

    private static final Logger logger = Logger.getLogger("AtomicInteger");

    /**
     * Returns the object from the 2 level cache
     */
    @Override
    public Object assemble(final Serializable cached, final Object owner)
            throws HibernateException {
        //would work as the AtomicInteger.class is Serializable, 
        //and stored in cache as it is - see disassemble
        return cached;
    }

    /**
     * Used to create Snapshots of the object
     */
    @Override
    public Object deepCopy(Object value) throws HibernateException {
        //return value; -> if AtomicInteger.class was immutable we could return the object as it is
        final AtomicInteger recievedParam = (AtomicInteger) value;
        final AtomicInteger atomicInteger = new AtomicInteger(recievedParam.get());
        return atomicInteger;
    }

    /**
     * method called when Hibernate puts the data in a second level cache. The
     * data is stored in a serializable form
     */
    @Override
    public Serializable disassemble(final Object value) throws HibernateException {
        //For this purpose the AtomicInteger.class must implement serializable
        return (Serializable) value;
    }

    /**
     * Used while dirty checking - control passed on to the
     * {@link AtomicInteger}
     */
    @Override
    public boolean equals(final Object o1, final Object o2) throws HibernateException {
        boolean isEqual = false;
        if (o1 == o2) {
            isEqual = true;
        }
        if (null == o1 || null == o2) {
            isEqual = false;
        } else {
            isEqual = o1.equals(o2);
        }
        return isEqual;
        //for this to work correctly the equals() 
        //method must be implemented correctly by AtomicInteger class
    }

    @Override
    public int hashCode(final Object value) throws HibernateException {
        return value.hashCode();
        //for this to work correctly the hashCode() 
        //method must be implemented correctly by AtomicInteger class

    }

    /**
     * Helps hibernate apply certain optimizations for immutable objects
     */
    @Override
    public boolean isMutable() {
        return true; //The audit fields can be modified
    }

    /**
     * This method retrieves the property value from the JDBC resultSet
     */
    @Override
    public Object nullSafeGet(ResultSet resultSet, String[] names, SharedSessionContractImplementor ssci, Object owner) throws HibernateException, SQLException {
        //owner here is class from where the call to retrieve data was made.
        //In this case the Test class
        AtomicInteger atomicInteger = null;
        if (!resultSet.wasNull()) {
            atomicInteger = new AtomicInteger(resultSet.getInt(names[0]));            
        }
        return atomicInteger;
    }

    /**
     * The method writes the property value to the JDBC prepared Statement
     *
     */
    @Override
    public void nullSafeSet(final PreparedStatement statement,
            final Object value, final int index, SharedSessionContractImplementor ssci) throws HibernateException,
            SQLException {
        if (null == value) {
            statement.setNull(index, java.sql.Types.INTEGER);
        } else {
            AtomicInteger atomicInteger = (AtomicInteger) value;
            if (null != atomicInteger) {
                statement.setInt(index , atomicInteger.get());
            } else {
                statement.setNull(index, java.sql.Types.INTEGER);
            }

        }
    }

    /**
     * Method used by Hibernate to handle merging of detached object.
     */
    @Override
    public Object replace(final Object original, final Object target,
            final Object owner)
            throws HibernateException {
        //return original; // if immutable use this
        //For mutable types at bare minimum return a deep copy of first argument
        return this.deepCopy(original);

    }

    /**
     * Method tells Hibernate which Java class is mapped to this Hibernate Type
     */
    @SuppressWarnings("rawtypes")
    @Override
    public Class returnedClass() {
        return AtomicInteger.class;
    }

    /**
     * Method tells Hibernate what SQL columns to use for DDL schema generation.
     * using the Hibernate Types leaves Hibernate free to choose actual SQl
     * types based on database dialect. (Alternatively SQL types can also be
     * used directly)
     */
    @Override
    public int[] sqlTypes() {
        //createdBy, createdDate,modifiedBy,modifiedDate
        return new int[]{java.sql.Types.INTEGER};
    }

}
在hibernate映射文件中,将Integer更改为AtomicIntegerType,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- Generated 12-sep-2017 13:14:50 by Hibernate Tools 4.3.1 -->
<hibernate-mapping>
   <class name="classs.location.Statistics" table="statistics" catalog="CATALOG" optimistic-lock="version">
      <id name="id" type="java.lang.Integer">
         <column name="id" />
         <generator class="identity" />
      </id>
      <property name="totalErrors" type="class.location.AtomicIntegerType">
         <column name="total_errors" />
      </property>
   </class>
</hibernate-mapping>


您在哪一行获得异常?提供更多信息。以及DAO/存储库(如果可能)。此外,我在您的Pojo中没有看到任何JPA或Hibernate注释。如果您也使用xml进行映射,请提供xml。在哪一行获得异常?提供更多信息。以及DAO/存储库(如果可能)。此外,我在您的Pojo中没有看到任何JPA或Hibernate注释。如果您也使用xml进行映射,请提供xml。谢谢!我尝试过,但在hibernate 5.2.10中不起作用。最后,这很奇怪,因为它出现在hibernate 5.2中documentation@martin我很确定问题出在hibernate映射xml文件上。尝试将
type=“java.lang.Integer”
调整为
type=“path.to.AtomicIntConverter”
谢谢!我尝试了一下,它抛出了一个新的异常:初始SessionFactory创建失败。org.hibernate.MappingException:无法确定java.lang.AtomicInteger的类型,位于表:statistics,列:[org.hibernate.mapping.Column(total_errors)]。我还认为这个解决方案应该是正确的,但是如果不需要更改映射xml文件,它就不起作用了。它应该只与AttributeConverter一起工作,但它会抛出相同的ExceptionAnks!我尝试过,但在hibernate 5.2.10中不起作用。最后,这很奇怪,因为它出现在hibernate 5.2中documentation@martin我很确定问题出在hibernate映射xml文件上。尝试将
type=“java.lang.Integer”
调整为
type=“path.to.AtomicIntConverter”
谢谢!我尝试了一下,它抛出了一个新的异常:初始SessionFactory创建失败。org.hibernate.MappingException:无法确定java.lang.AtomicInteger的类型,位于表:statistics,列:[org.hibernate.mapping.Column(total_errors)]。我还认为这个解决方案应该是正确的,但是如果不需要更改映射xml文件,它就不起作用了。它应该只适用于AttributeConverter,但它抛出了相同的异常,UserType也适用,但是考虑到您必须提供的所有实现细节,它比编写简单的转换器更容易出错。但很高兴你找到了一个有效的解决方案。当然!而且实现起来更容易,但无论如何它都不起作用。非常感谢你的帮助!当然,UserType也可以工作,但是考虑到您必须提供的所有实现细节,它比编写简单的转换器更容易出错。但很高兴你找到了一个有效的解决方案。当然!而且实现起来更容易,但无论如何它都不起作用。非常感谢你的帮助!