java - 来自多个数据库的 Hibernate 实体

标签 java database hibernate usertype

我们的数据模型被分成两个数据库的模式。除了在两者之间架起桥梁的少数单键关系外,这些模式是独立使用的。没有跨越两个数据库的写入事务。

类似这个问题Doing a join over 2 tables in different databases using Hibernate ,我们想使用 Hibernate 来处理加入实体。我们不能使用数据库解决方案(DB2 上的联合 View )。

我们已经为 Hibernate 设置了两个独立的数据库配置(医生和患者),这在使用 DAO 显式访问特定 session 时完美运行。

我们希望在调用 DoctorBO.getExam().getPatient() 时使用 Hibernate 自动检索实体,其中 examination 包含一个指向其他数据库中 Patient 表的 id。

我尝试过的一种方法是使用自定义 UserType:

public class DistributedUserType implements UserType, ParameterizedType
{
    public static final String CLASS = "CLASS";
    public static final String SESSION = "SESSION";

    private Class<? extends DistributedEntity> returnedClass;
    private String session;

    /** {@inheritDoc} */
    @Override
    public int[] sqlTypes()
    {
        // The column will only be the id
        return new int[] { java.sql.Types.BIGINT };
    }

    /** {@inheritDoc} */
    @Override
    public Class<? extends DistributedEntity> returnedClass()
    {
        // Set by typedef parameter
        return returnedClass;
    }

    /** {@inheritDoc} */
    @Override
    public boolean equals(Object x, Object y) throws HibernateException
    {
        if (x == y)
        {
            return true;
        }

        if ((x == null) || (y == null))
        {
            return false;
        }

        Long xId = ((DistributedEntity) x).getId();
        Long yId = ((DistributedEntity) y).getId();

        if (xId.equals(yId))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    /** {@inheritDoc} */
    @Override
    public int hashCode(Object x) throws HibernateException
    {
        assert (x != null);
        return x.hashCode();
    }

    /** {@inheritDoc} */
    @Override
    public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException
    {
        Long id = rs.getLong(names[0]);
        return HibernateUtils.getSession(session).get(returnedClass, id);
    }

    /** {@inheritDoc} */
    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException
    {
        DistributedEntity de = (DistributedEntity) value;
        st.setLong(index, de.getId());
    }

    /** {@inheritDoc} */
    @Override
    public Object deepCopy(Object value) throws HibernateException
    {
        return value;
    }

    /** {@inheritDoc} */
    @Override
    public boolean isMutable()
    {
        return false;
    }

    /** {@inheritDoc} */
    @Override
    public Serializable disassemble(Object value) throws HibernateException
    {
        return (Serializable) value;
    }

    /** {@inheritDoc} */
    @Override
    public Object assemble(Serializable cached, Object owner) throws HibernateException
    {
        return cached;
    }

    /** {@inheritDoc} */
    @Override
    public Object replace(Object original, Object target, Object owner) throws HibernateException
    {
        return original;
    }

    /** {@inheritDoc} */
    @Override
    public void setParameterValues(Properties parameters)
    {
        String clazz = (String) parameters.get(CLASS);
        try
        {
            returnedClass = ReflectHelper.classForName(clazz);
        }
        catch (ClassNotFoundException e)
        {
            throw new IllegalArgumentException("Class: " + clazz + " is not a known class type.");
        }

        session = (String) parameters.get(SESSION);
    }
}

然后将使用:

@TypeDef(name = "testUserType", typeClass = DistributedUserType.class, parameters = {
                                                                                 @Parameter(name = DistributedUserType.CLASS, value = PatientBO.CLASSNAME),
                                                                                 @Parameter(name = DistributedUserType.SESSION, value = HibernateUtils.PATIENT_SESS) })

@Type(type = "testUserType")
@Column(name = "PATIENT_ID")
private PatientBO patient;

UserType 有效 - 数据正确加载,只有字段的 Id 持久保存到数据库中。我已经测试了 doctor.getExam().getPatient()doctor.getExam().setPatient() 的非常简单的示例,两者似乎都很好用,但我认为这是一个可怕的 hack,我没有足够的 Hibernate 知识来知道这是否可以安全使用。

是否有更好的方法来实现我们想要的?我在这里描述的方式是否足够,或者是否会在未来造成困难?

最佳答案

我认为这不是个好主意。您试图“好像”一切都在一个数据库中,但事实并非如此。而且您“好像”在检查和患者之间存在真正的 toOne 关联,尽管这不是真正的关联。

虽然您意识到了这一事实,但其他或 future 的开发人员不一定会,并且会想知道为什么不可能进行如下查询

select e from Exam e left join fetch e.patient

select e from Exam e where e.patient.name like 'Smith%'

简而言之,您的伪协会只履行了常规协会提供的契约(Contract)的一小部分,在我看来,这会造成更多的困惑而不是安慰。

没有什么能阻止你拥有像这样的实用方法

Patient getExamPatient(Exam e)

它做同样的事情,但清楚地表明两个实体之间没有真正的关联。

关于java - 来自多个数据库的 Hibernate 实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8980857/

相关文章:

java - 无法执行插入/更新/删除

java - 是否有用于 x64 的 JNI 共享 stub 实现?

java - 使用batchUpdate时NamedParameterJdbcTemplate不更新

database - sqoop 从 db2 特定模式导入所有到配置单元

php - SQL 查询来查找特定博客文章的作者?

java - 在 hibernate org.hibernate.hql.internal.ast.QuerySyntaxException 中更新表时

hibernate - HHH000122 : IllegalArgumentException in class: ConsumerAgentAccount, 属性的getter方法:id

Java 有效日期闰年

java - 如何赋予 JButton 不同的功能?

java - 针对少量和长时间 GC 运行的 JVM 调优