Grails - 如何在服务中保存域对象?

发布于 2024-10-09 18:02:17 字数 2890 浏览 0 评论 0原文

我有一项服务,在其中一个函数中我正在创建一个域对象并尝试保存它。
当它到达保存部分时,我收到错误

没有 Hibernate 会话绑定到线程, 并且配置不允许 在这里创建非事务性的

我需要做什么才能将域对象保存在服务中。互联网上的所有内容都使它看起来应该可行......

编辑:
其他详细信息: 我偶然发现了这篇文章
线程中的 Hibernate 会话

这是一个类似的场景。我的服务被第三方 API 调用。

编辑:
我没有很好地解释这一点。这是更完整的代码,

import org.springframework.beans.factory.InitializingBean
import com.ib.client.EWrapper;


class BrokerService implements InitializingBean, EWrapper{

    static transactional = true

    private EClientSocket m_client
    private boolean m_disconnectInProgress = false

    void afterPropertiesSet(){
       // this.setting = grailsApplication1.config.setting
       m_client = new EClientSocket(this)
       m_disconnectInProgress = false

       connect()
    }


    def boolean connect() {
        m_client.eConnect()
        if (m_client.isConnected())
            return true

        return false
 }

    def void historicalData(int reqId, String date, double open,
   double high, double low, double close, int volume, int count,
   double WAP, boolean hasGaps)
    {   
        HistoricalContractData.withNewSession{session->
            println ' just before object create'
            def hcd = new sbi.investments.HistoricalContractData()
            hcd.hc_id = reqId
            hcd.data_date = new Date().parse('yyyyMMdd', date.replace('finished-', ''))
            hcd.open = open
            hcd.high = high
            hcd.low = low
            hcd.close = close
            hcd.volume =volume
            hcd.trade_count =count
            hcd.wap = WAP
            hcd.has_gaps = hasGaps.toString()
            println ' just before save'
            hcd.save()

            if(hcd.hasErrors()){
                println '=========== ERROR! ============'
                println hcd.errors
            }
        }
 }
}

第 3 方 API 多次调用历史数据。使用上面的代码,它保存第一条记录,但在第二条记录上我收到错误:

无法打开休眠会话; 嵌套异常是 org.hibernate.SessionException: 会议已结束!

编辑:
因此,更多地阅读此内容,我想我明白发生了什么。
当从控制器调用时,休眠会话通常会注入到服务中。
由于历史数据是从第三方应用程序调用的,而不是通过控制器调用的,因此没有休眠会话被注入到服务中,因此它会抱怨会话已关闭。

所以我认为真正的问题可能是,如果没有从控制器调用服务,我如何创建一个新的休眠会话以保存 grails 域模型对象(即 HistoricalContractData)。
从上面可以看出,withNewSession 不起作用。我应该像这样使用 SessionFactory 吗?
(无法发布源链接,因为堆栈溢出不喜欢它)

import org.hibernate.Session;
import org.hibernate.SessionFactory;

public class YourService  {

    SessionFactory sessionFactory // set by Dependency Injection

    public void yourMethod() {
        Session session = sessionFactory.getCurrentSession();
        // do something with session
    }
}

我尝试过这个,但不明白如何使用会话对象来保存 HistoricalContractData 对象。

I have a service and inside one of the functions i'm creating a domain object and trying to save it.
when it gets to the save part, i get the error

No Hibernate Session bound to thread,
and configuration does not allow
creation of non-transactional one here

What do i need to do in order to save a domain object inside of a service. everything on the internet makes it look like this should just work....

Edit:
additional details:
I stumbled across this post
Hibernate session in threads

which is a similar scenario. My service is getting called by a 3rd party API.

Edit:
I'm not explaining this very well. Here is more complete code

import org.springframework.beans.factory.InitializingBean
import com.ib.client.EWrapper;


class BrokerService implements InitializingBean, EWrapper{

    static transactional = true

    private EClientSocket m_client
    private boolean m_disconnectInProgress = false

    void afterPropertiesSet(){
       // this.setting = grailsApplication1.config.setting
       m_client = new EClientSocket(this)
       m_disconnectInProgress = false

       connect()
    }


    def boolean connect() {
        m_client.eConnect()
        if (m_client.isConnected())
            return true

        return false
 }

    def void historicalData(int reqId, String date, double open,
   double high, double low, double close, int volume, int count,
   double WAP, boolean hasGaps)
    {   
        HistoricalContractData.withNewSession{session->
            println ' just before object create'
            def hcd = new sbi.investments.HistoricalContractData()
            hcd.hc_id = reqId
            hcd.data_date = new Date().parse('yyyyMMdd', date.replace('finished-', ''))
            hcd.open = open
            hcd.high = high
            hcd.low = low
            hcd.close = close
            hcd.volume =volume
            hcd.trade_count =count
            hcd.wap = WAP
            hcd.has_gaps = hasGaps.toString()
            println ' just before save'
            hcd.save()

            if(hcd.hasErrors()){
                println '=========== ERROR! ============'
                println hcd.errors
            }
        }
 }
}

the 3rd party API is calling historicalData several times. With the above code, it is saving the first record, but then on the 2nd record i'm getting the error:

Could not open Hibernate Session;
nested exception is
org.hibernate.SessionException:
Session is closed!

Edit:
so reading up on this more i think i understand what is happening.
a hibernate session is usually injected into the Service when called from the controller.
Because historicalData is being called from a 3rd party app and not via a controller, no hibernate session is getting injected into the service so it complains that the Session is closed.

So I think the real question may be, if a service is not called from a controller, how do i create a new hibernate session in order to save a grails domain model object (i.e. HistoricalContractData).
As can be seen above, withNewSession is not working. Should i be using a SessionFactory like so ?
(can't post link to source because stack overflow doesn't like it)

import org.hibernate.Session;
import org.hibernate.SessionFactory;

public class YourService  {

    SessionFactory sessionFactory // set by Dependency Injection

    public void yourMethod() {
        Session session = sessionFactory.getCurrentSession();
        // do something with session
    }
}

I kind of tried this but don't understand how to use the session object in order to save the HistoricalContractData object.

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

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

发布评论

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

评论(2

新雨望断虹 2024-10-16 18:02:17

默认情况下,服务方法应该是事务性的,并且具有会话。如果不是,您可能没有遵循 Grails 约定:

  1. 您的服务是否位于 grails-app 的 services 目录中?
  2. 您的服务名称/文件是否以“Service”结尾?
  3. 您是否以某种方式使服务或服务方法本身不是事务性的?
  4. 您不是从控制器调用服务吗?
  5. 您是否使用依赖注入将您的服务引入到您使用的任何地方?

也就是说,您始终可以通过使用

AnyDomainObject.withTransaction{txStatus->
// do stuff like save here
}

执行或创建一个新会话

AnyDomainObject.withNewSession{session->
// do stuff here
}

您拥有的没有关闭所需的“箭头”的代码

来创建事务。编辑,对于您的更新,您应该签出

http: //docs.jboss.org/hibernate/core/3.6/reference/en-US/html/objectstate.html

了解如何使用会话。基本上,你应该能够做到这一点

session.save(hcd)

此外,你可能能够像在grails中一样你调用sessionFactory.getCurrentSession()之后执行hcd.save() - - 我认为这可能有效的原因是该方法应该创建一个新会话并通过 threadlocal 将其绑定到当前线程。

Service methods should be transactional, and have a session, by default. If they are not, you are probably not following Grails conventions somehow:

  1. Is your service in the services directory of grails-app?
  2. Does your service name/file end with 'Service'?
  3. Did you make the service or service method itself not transactional somehow?
  4. Are you not invoking the service from a controller?
  5. Are you using dependency injection to get your services into where-ever you use them?

That said, you can always create a transaction by doing

AnyDomainObject.withTransaction{txStatus->
// do stuff like save here
}

or create a new session with

AnyDomainObject.withNewSession{session->
// do stuff here
}

the code you have does not have the 'arrow' that is necessary for closures.

EDIT, for you updates, you should checkout

http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/objectstate.html

on how to use the session. Basically, you should be able to do just

session.save(hcd)

Also, you might be able to do hcd.save() like normal in grails after you call the sessionFactory.getCurrentSession() -- the reason I think this might work is that method should create a new session and bind it to the current thread via threadlocal.

蓝梦月影 2024-10-16 18:02:17

您需要为您的服务指定事务上下文。确保您的 Grails 服务是按这种方式完成的。

另一个 Grails 服务链接:

http://www .grails.org/doc/1.0.x/guide/8.%20The%20Service%20Layer.html

You need to specify a transaction context for your service. Make sure your Grails services are done this way.

Another Grails service link:

http://www.grails.org/doc/1.0.x/guide/8.%20The%20Service%20Layer.html

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