如何使Spring实例化自定义ID生成器而不是休眠?

时间:2019-07-21 19:19:12

标签: hibernate spring-boot spring-mvc

I am trying to use a custom ID generator in Spring-MVC boot application.
But instead of Spring creating an instance of ID generator, hibernate is creating it and
hence I am getting NullPointerException when I access autowired dependencies of ID generator. 
**How can I tell hibernate not to create an instance of the Custom ID generator and allow Spring to do it?**

我尝试将@Component添加到自定义ID生成器类中,但是似乎休眠始终在创建实例。 我也经历过Configure custom hibernate id generator in spring context,但不明白如何解决此问题。       代码段如下:

实体类

实体类:这是我在策略自定义ID生成器(即要使用的KE_IDGenerator)中提到的模型类。

    @Entity
    @Table(name="TAB_Error")
    public class KnownErrorDto {
        @Id
        @GenericGenerator(name="seq_id", strategy="x.x.x.x.IdGenerator.KE_IDGenerator"
                )
        @GeneratedValue(generator="seq_id")
        @Column(name ="KEID")
        String KEID;
    }
    _____________________________________________________________________________

道课     道:在此界面中,我提到了一种使用本机查询的方法,该方法给出下一个序列值。

public interface KnownErrorDaoInterface extends CrudRepository<KnownErrorDto,Integer> {
 @Query(value = "SELECT TAB_Err_SEQ.nextval  FROM dual", nativeQuery = 
                true)
     int getNextSeqForKnownError();

    }
    _____________________________________________________________________________

自定义ID生成器类

自定义ID生成器:这是一个从Dao获取序列值并应返回自定义ID的类

public class KE_IDGenerator implements IdentifierGenerator {

        @Autowired
        KnownErrorDaoInterface knownErrorDaoInterface;

    @Override
        public Serializable generate(SharedSessionContractImplementor session, Object object)
                    throws HibernateException {

                String prefix = "KE";

                int id=knownErrorDaoInterface.getNextSeqForKnownError();
                String keId=null;

                keId=prefix + StringUtils.leftPad("" + id,9, '0');
                return keId;
            }
        }
   _____________________________________________________________________________ 

我将遇到错误:

2019-07-21 20:11:11.165 ERROR 1900 --- [nio-8083-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
    java.lang.NullPointerException: null
        at 
x.x.x.x.IdGenerator.KE_IDGenerator.generate(KE_IDGenerator.java:27) ~[classes/:na]

我希望KE_IDGenerator使用KnownErrorDaoInterface提供的序列值生成自定义ID。但是,当我尝试访问KnownErrorDaoInterface时,我得到的是空指针。

2 个答案:

答案 0 :(得分:0)

您的自定义Id生成器KE_IDGenerator不是受Spring管理的bean,它将由spring管理,因此您不能在其中注入任何依赖项。 knownErrorDaoInterface将始终为null。如果要使用现有序列表进行ID生成,可以像这样

使用它
@Entity
@Table(name="TAB_Error")
public class KnownErrorDto {
    @Id
    @GeneratedValue(generator="seq_name")
@SequenceGenerator(name="seq_name",sequenceName="seq_table",allocationSize=10)
    @Column(name ="KEID")
    String KEID;
}

答案 1 :(得分:0)

您可以在自定义生成器中使用 session 方法中的 generate 参数来执行本机语句。 这样做需要您编写自定义 SQL 语句并消除 Spring 和 Hibernate 处理它的舒适性,但它可以完成这项工作。

public class FimIdGenerator extends SequenceStyleGenerator {
    
    @Override
    public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {

        // The object, that shall get a new ID is provided as `Object object`
        // So feel free to cast it to your own entity
        if(object instanceof FimEntity){
            FimEntity entity = (FimEntity) object;

            String createQuery = "CREATE SEQUENCE IF NOT EXISTS MY_CUSTOM_SEQENCE_NAME"
            session.createSQLQuery(createQuery).executeUpdate();

            String nextValQuery = "SELECT NEXTVAL('MY_CUSTOM_SEQENCE_NAME')";
            BigInteger newId = (BigInteger) session.createSQLQuery(nextValQuery).getSingleResult();

            return newId;
        }else{
            throw new HibernateException("Only entities of super type FimEntity are supported");
        }
    }
}

现在,这个例子使用了一个固定的序列名称,这不是我们都需要的,我们需要动态名称。所以我所做的是:

班级水平

private final static String CREATE_TEMPLATE = "CREATE SEQUENCE IF NOT EXISTS SEQ_%03d_%s START WITH 1";

private final static String NEXTVAL_TEMPLATE = "SELECT NEXTVAL('SEQ_%03d_%s');";

generate 方法级别(fimId 对象是我的实体的一方,我只是 getFimId() 在铸造的 object 上)

String createQuery = String.format(CREATE_TEMPLATE, fimId.getAppiid(), fimId.getEntityType());
session.createSQLQuery(createQuery).executeUpdate();

String nextValQuery = String.format(NEXTVAL_TEMPLATE, fimId.getAppiid(), fimId.getEntityType());
BigInteger newId = (BigInteger) session.createSQLQuery(nextValQuery).getSingleResult();

这样做会在运行时创建新的序列,例如“SEQ_001_tag”或租户 1 和实体类型标签或租户 16 和实体类型文档的“SEQ_016_document”。