在Hibernate中选择查询时阻止插入

Dea*_*eam 4 select hibernate insert one-to-one

我是Hibernate的新手.我有一个问题,当我试图运行选择查询说

"from Foo where Foo.some_id=2"
Run Code Online (Sandbox Code Playgroud)

(使用Hibernate模板)然后Hibernate也尝试将记录插入到表'Foo2'中,该表与Foo表具有一对二的关联

Bean Foo

class Foo{
int id;
....
Foo2 foo2;
}
Run Code Online (Sandbox Code Playgroud)

Foo.hbm.xml

...
<one-to-one name="foo2" class="Foo2" property-ref="foo"
  constrained="false" cascade="save-update"></one-to-one>
...
Run Code Online (Sandbox Code Playgroud)

Bean Foo2

Class Foo2{
...
private int foo;
...
}
Run Code Online (Sandbox Code Playgroud)

Foo2.hbm.xml

...
<property name="foo" column="foo_id"/>
...
Run Code Online (Sandbox Code Playgroud)

用法

 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);
    }   
Run Code Online (Sandbox Code Playgroud)

这就是我得到的......

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
Run Code Online (Sandbox Code Playgroud)

Pas*_*ent 5

我的猜测是你在会话中有待更改(一些Foo2实例等待插入),默认情况下,Hibernate会在运行查询之前刷新会话,以便为您提供非陈旧的结果.这在文档的以下部分中进行了解释:

10.10.刷新会话

有时,Session将执行将JDBC连接的状态与内存中保存的对象状态同步所需的SQL语句.此过程称为刷新,默认情况下发生在以下几点:

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

SQL语句按以下顺序发出:

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

一个例外是在保存时会插入使用本机ID生成的对象.

除非您明确说明flush(),否则绝对不能保证Session何时执行JDBC调用,只保证它们执行的顺序.但是,Hibernate确保 Query.list(..)永远不会返回过时或不正确的数据.

可以更改默认行为,以便更频繁地进行刷新.的FlushMode类定义了三种不同的模式:仅刷新在提交时用于Hibernate的Transaction API时,自动冲水使用解释程序中,或从未除非冲洗冲洗()被明确地调用.最后一种模式对于长时间运行的工作单元很有用,其中会话保持打开和断开很长时间(参见第11.3.2节"扩展会话和自动版本控制").

sess = sf.openSession();
Transaction tx = sess.beginTransaction();
sess.setFlushMode(FlushMode.COMMIT);
Run Code Online (Sandbox Code Playgroud)

//允许查询返回失效状态

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();
Run Code Online (Sandbox Code Playgroud)

在刷新期间,可能会发生异常(例如,如果DML操作违反约束).由于处理异常涉及对Hibernate的事务行为的一些理解,因此我们将在第11章"事务和并发"中讨论它.

因此,如上所述并如代码段所示,请尝试使用FlushMode.COMMIT.

请注意,如果您使用的是identity生成器,这将无济于事,Hibernate会save及时写入数据库.

另外请注意,FlushMode仅仅是一个暗示Session,该行为不是严格的保证.