【问题标题】:Spring hibernate transactions - catch 22春季休眠事务 - 捕获 22
【发布时间】:2012-02-19 16:16:38
【问题描述】:

我将 Spring 和 Hibernate 与注释驱动的事务一起使用。 运行我的应用程序时,我收到一个异常“createCriteria is not valid without active transaction”。根据这个Spring/Hibernate Exception: createCriteria is not valid without active transaction,解决方案是从sessionFactory配置中删除<property name="current_session_context_class">thread</property>这一行。

但是,我还需要在 @PostConstruct 方法中做一些事务性工作(从 DB 初始化)。 @PostConstruct 方法不能是事务性的,所以我打开了一个手动事务 - 但是当我删除上面的行时这不起作用(得到一个异常 org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here)。根据几个消息来源,解决方案是将<property name="current_session_context_class">thread</property> 添加到配置中......

这是我的代码(我知道它不太干净 - 我一直在摆弄它以了解问题所在):

`@Transactional 公共类 TaskControllerImpl 实现 TaskController {

@Autowired
TaskDAO taskDAO;

@Autowired
MethodDAO methodDAO;

@Autowired
SessionFactory sessionFactory;

ExecutorService threadPool = Executors.newCachedThreadPool();


/**
 * Map of method name to TaskExecutor for all defined methods
 */
private Map<String, TaskExecutor> executorsByMethod;

final Logger logger = LoggerFactory.getLogger(TaskControllerImpl.class);

/**
 * Initializes the mapping of method name to TaskExecutor
 */
@PostConstruct
public void init() {
    // @Transactional has no effect in @Postconstruct methods so must do this manually
    Transaction t = sessionFactory.getCurrentSession().beginTransaction();
    executorsByMethod = new HashMap<String, TaskExecutor>();
    List<Method> methods = methodDAO.findAll();
    for (Method method : methods) {         
        if (method.getExecutorClassName() != null) {
            try {
                TaskExecutor executor = createTaskExecutor(method);
                executorsByMethod.put(method.getName(), executor);
            } catch (Throwable e) {
                logger.error("Coud not create/instantiate executor " + method.getExecutorClassName());
                e.printStackTrace();
            }
        }       
    }

    t.commit();
}

@Override
public void run() {
    Collection<Task> tasksToExecute = fetchTasksToExecute();
    for (Task task : tasksToExecute) {
        String method = task.getMethod().getName();
        executorsByMethod.get(method).addTask(task);
    }
}

/**
 * Fetches all tasks which need to be executed at the current time
 * 
 * @return
 */
private Collection<Task> fetchTasksToExecute() {
    try {
        Search search = new Search();
        search.addFilterLessThan("actionDate", DateUtil.now());
        search.addFilterEqual("status", TaskStatus.PENDING.getCode());
        search.addSort("actionDate", false);
        return taskDAO.search(search);
    } catch (Throwable e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        return null;
    }
}

`

配置:

`

<!-- Configure a JDBC datasource for Hibernate to connect with -->
<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="${connection.url}" />
    <property name="username" value="${connection.username}" />
    <property name="password" value="${connection.password}" />
</bean>

<!-- Configure a Hibernate SessionFactory -->
<bean id="sessionFactory"
    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan" value="com.grroo.model" />
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="hibernate.show_sql">false</prop>
            <!-- prop key="hibernate.current_session_context_class">thread</prop-->
            <prop key="hibernate.connection.zeroDateTimeBehavior">convertToNull</prop>
        </props>
    </property>
</bean>

<bean id="transactionManager"
    class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:annotation-driven/> 

`

所以我在这里有点关于如何使 init() 和 run() 工作的问题 22。有什么想法吗?

【问题讨论】:

标签: hibernate spring transactions


【解决方案1】:

您只需要从 postconstruct 中提取您的事务方法,然后调用它。例如:

@PostConstruct
public void postConstruct(){
    init();
}

@Transactional
public void init(){
    ...
}

【讨论】:

  • 谢谢,但它不起作用(根据 Spring 文档,@Transactional 不会在内部方法调用上调用 - 仅在 bean 外部的调用上)。不过,我可能会使用类似的东西 - 定义一个 boolean initialized 并在第一次调用时从 run() 调用 init(没有 @postconstruct)。
  • 也许您在 上使用了 mode=aspectj 或 proxy_target_class=true?我认为它适用于这种情况,但我不想仅仅为此而改变
  • 啊...你是对的,我正在使用 proxy_target_class。您可以在另一个 bean 的 PostConstruct 中执行 init(),例如 Configuration 类。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-04
  • 1970-01-01
  • 2013-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-14
相关资源
最近更新 更多