在 Hibernate 中防止 select 查询时插入

发布于 2024-09-27 00:44:11 字数 2498 浏览 5 评论 0原文

我是休眠新手。我有一个问题,当我尝试运行选择查询

"from Foo where Foo.some_id=2"

(使用 Hibernate 模板)时,Hibernate 也会尝试将记录插入到与 Foo 表

Bean Foo

class Foo{
int id;
....
Foo2 foo2;
}

Foo 具有一对二一关联的表“Foo2”中.hbm.xml

...
<one-to-one name="foo2" class="Foo2" property-ref="foo"
  constrained="false" cascade="save-update"></one-to-one>
...

Bean Foo2

Class Foo2{
...
private int foo;
...
}

Foo2.hbm.xml

...
<property name="foo" column="foo_id"/>
...

用法

 DetachedCriteria criteria = createDetachedCriteria();
  criteria.add(Restrictions.eq("some_id", value));
  return getHibernateTemplate().findByCriteria(criteria);

    public List<SnsUser> getAllSnsUsersByProperty(String prop, Object val){
            String query = "from SnsUser su where su." + prop + " =:" + prop;
            return executeQuery(query, new String[]{prop}, new Object[]{val});
    }

    public static void main(String[] args) { //WORKING
    String query = "from SnsUser su where su.blessUserId=1";
    Session session = Utility.getSessionFactory().openSession();
    List l = new SnsUserDaoImpl().getQRes(query);
    System.out.println(l);
    session.close();
    }
public List<E> executeQuery(String queryString, String []param, Object [] val){
//NOT WORKING
        return getHibernateTemplate().findByNamedParam(queryString, param, val);
    }   

这就是我得到的...

Hibernate: select * from bless_aggregation.sns_user this_ left outer join bless_aggregation.sns_authenticator snsauthent2_ on this_.sns_uid=snsauthent2_.sns_uid 
where this_.bless_uid=?
Hibernate: select * from bless_aggregation.bless_user blessuser0_ where blessuser0_.bless_uid=?
Hibernate: select * from bless_aggregation.sns_user snsuser0_ left outer join bless_aggregation.sns_authenticator snsauthent1_ on 
snsuser0_.sns_uid=snsauthent1_.sns_uid where snsuser0_.bless_uid=?

Hibernate: insert into bless_aggregation.sns_authenticator (key, value, sns_uid) values (?, ?, ?)
1079 [main] WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 1064, SQLState: 42000
1079 [main] ERROR org.hibernate.util.JDBCExceptionReporter - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'key, value, sns_uid) values (null, null, 1)' at line 1

I am new to Hibernate. I have a problem that when I am trying to run select query say

"from Foo where Foo.some_id=2"

(with Hibernate template) then Hibernate is also tries to insert the records in a table 'Foo2' that has a one-2-one association with the Foo table

Bean Foo

class Foo{
int id;
....
Foo2 foo2;
}

Foo.hbm.xml

...
<one-to-one name="foo2" class="Foo2" property-ref="foo"
  constrained="false" cascade="save-update"></one-to-one>
...

Bean Foo2

Class Foo2{
...
private int foo;
...
}

Foo2.hbm.xml

...
<property name="foo" column="foo_id"/>
...

Usage

 DetachedCriteria criteria = createDetachedCriteria();
  criteria.add(Restrictions.eq("some_id", value));
  return getHibernateTemplate().findByCriteria(criteria);

    public List<SnsUser> getAllSnsUsersByProperty(String prop, Object val){
            String query = "from SnsUser su where su." + prop + " =:" + prop;
            return executeQuery(query, new String[]{prop}, new Object[]{val});
    }

    public static void main(String[] args) { //WORKING
    String query = "from SnsUser su where su.blessUserId=1";
    Session session = Utility.getSessionFactory().openSession();
    List l = new SnsUserDaoImpl().getQRes(query);
    System.out.println(l);
    session.close();
    }
public List<E> executeQuery(String queryString, String []param, Object [] val){
//NOT WORKING
        return getHibernateTemplate().findByNamedParam(queryString, param, val);
    }   

This is what i am getting...

Hibernate: select * from bless_aggregation.sns_user this_ left outer join bless_aggregation.sns_authenticator snsauthent2_ on this_.sns_uid=snsauthent2_.sns_uid 
where this_.bless_uid=?
Hibernate: select * from bless_aggregation.bless_user blessuser0_ where blessuser0_.bless_uid=?
Hibernate: select * from bless_aggregation.sns_user snsuser0_ left outer join bless_aggregation.sns_authenticator snsauthent1_ on 
snsuser0_.sns_uid=snsauthent1_.sns_uid where snsuser0_.bless_uid=?

Hibernate: insert into bless_aggregation.sns_authenticator (key, value, sns_uid) values (?, ?, ?)
1079 [main] WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 1064, SQLState: 42000
1079 [main] ERROR org.hibernate.util.JDBCExceptionReporter - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'key, value, sns_uid) values (null, null, 1)' at line 1

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

七禾 2024-10-04 00:44:11

我的猜测是,您在会话中有挂起的更改(一些 Foo2 实例等待插入),并且默认情况下,Hibernate 在运行查询之前刷新会话以提供非过时的结果。文档的以下部分对此进行了解释:

10.10。刷新会话

有时会话会执行
需要同步的SQL语句
JDBC 连接的状态
内存中保存的对象的状态。这
称为刷新的过程发生于
默认在以下几点:

  • 在执行某些查询之前
  • 来自 org.hibernate.Transaction.commit()
  • 来自 Session.flush()

SQL 语句在
以下顺序:

  1. 所有实体插入的顺序与相应对象的顺序相同
    使用 Session.save()
  2. 保存

  3. 所有实体更新
  4. 所有集合删除
  5. 所有集合元素删除、更新和插入
  6. 所有集合插入
  7. 所有实体删除的顺序与相应对象的顺序相同
    使用 Session.delete() 删除

一个例外是对象使用
本机 ID 生成在以下情况插入
他们得救了。

除非您显式flush()
绝对没有任何保证
关于Session何时执行
JDBC调用,只需要顺序
他们被处决了。 但是,休眠
确实保证了
Query.list(..) 永远不会返回
过时或不正确的数据

可以更改默认值
行为使冲洗发生更少
经常
。 FlushMode 类
定义了三种不同的模式:
在提交时刷新
使用Hibernate Transaction API

使用自动冲洗
解释常规,或永不冲水
除非明确调用了flush()。
最后一种模式可以长期使用
运行工作单元,其中会话
保持打开和断开状态
长时间(参见第 11.3.2 节,
“延长会话和自动
版本控制”)。

sess = sf.openSession();
交易 tx = sess.beginTransaction();
sess.setFlushMode(FlushMode.COMMIT);

// 允许查询返回过时状态

Cat izi = (Cat) sess.load(Cat.class, id);
izi.setName(iznizi);

// 可能会返回过时的数据
sess.find("来自 Cat as cat left external join cat.kittens kitten");

// 更改为 izi 不会刷新!
...
tx.commit(); // 发生刷新
sess.close();

flush过程中可能会出现异常
(例如,如果 DML 操作违反了
约束)。由于处理异常
涉及到一些理解
Hibernate的事务行为,我们
在第 11 章“交易”中讨论
和并发性。

因此,正如上面所解释的和代码片段中所示,尝试使用FlushMode.COMMIT

请注意,如果您使用 identity 生成器,这将无济于事,Hibernate 将在 save 时写入数据库。

另请注意,FlushMode 只是 Session提示,其行为并未得到严格保证。

My guess is that you have pending changes in the session (some Foo2 instances waiting to be inserted) and, by default, Hibernate flushes the session before running a query to give you non stale results. This is explained in the following section of the documentation:

10.10. Flushing the Session

Sometimes the Session will execute the
SQL statements needed to synchronize
the JDBC connection's state with the
state of objects held in memory. This
process, called flush, occurs by
default at the following points:

  • before some query executions
  • from org.hibernate.Transaction.commit()
  • from Session.flush()

The SQL statements are issued in the
following order:

  1. all entity insertions in the same order the corresponding objects were
    saved using Session.save()
  2. all entity updates
  3. all collection deletions
  4. all collection element deletions, updates and insertions
  5. all collection insertions
  6. all entity deletions in the same order the corresponding objects were
    deleted using Session.delete()

An exception is that objects using
native ID generation are inserted when
they are saved.

Except when you explicitly flush(),
there are absolutely no guarantees
about when the Session executes the
JDBC calls, only the order in which
they are executed. However, Hibernate
does guarantee that the
Query.list(..) will never return
stale or incorrect data
.

It is possible to change the default
behavior so that flush occurs less
frequently
. The FlushMode class
defines three different modes: only
flush at commit time when the
Hibernate Transaction API is used
,
flush automatically using the
explained routine, or never flush
unless flush() is called explicitly.
The last mode is useful for long
running units of work, where a Session
is kept open and disconnected for a
long time (see Section 11.3.2,
“Extended session and automatic
versioning”).

sess = sf.openSession();
Transaction tx = sess.beginTransaction();
sess.setFlushMode(FlushMode.COMMIT);

// allow queries to return stale state

Cat izi = (Cat) sess.load(Cat.class, id);
izi.setName(iznizi);

// might return stale data
sess.find("from Cat as cat left outer join cat.kittens kitten");

// change to izi is not flushed!
...
tx.commit(); // flush occurs
sess.close();

During flush, an exception might occur
(e.g. if a DML operation violates a
constraint). Since handling exceptions
involves some understanding of
Hibernate's transactional behavior, we
discuss it in Chapter 11, Transactions
and Concurrency.

So, as explained above and as shown in the code snippet, try to use FlushMode.COMMIT.

Note that this won't help if you are using an identity generator, Hibernate will write to the database at save time.

Also note that the FlushMode is just an hint for the Session, the behavior is not strictly guaranteed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文