如何使用休眠设置 UserTransaction
How to set up UserTransaction with hibernate
我有一个用于管理用户信息的 mySQL 数据库,我的 mySQL 数据库使用 JTA 数据源,下面是 persistence.xml 的样子:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="SensorCloudPU" transaction-type="JTA">
<jta-data-source>java:/SensorCloudPU</jta-data-source>
<!-- <non-jta-data-source>java:/SensorCloudPU</non-jta-data-source> -->
<class>com.sensorhound.common.domain.impl.AnomalousInfo</class>
<class>com.sensorhound.common.domain.impl.Code</class>
<class>com.sensorhound.common.domain.impl.Device</class>
<class>com.sensorhound.common.domain.impl.Executable</class>
<class>com.sensorhound.common.domain.impl.Group</class>
<class>com.sensorhound.common.domain.impl.GroupAlert</class>
<class>com.sensorhound.common.domain.impl.GroupRule</class>
<class>com.sensorhound.common.domain.impl.GroupRuleDefinition</class>
<class>com.sensorhound.common.domain.impl.GroupRuleStatus</class>
<class>com.sensorhound.common.domain.impl.Node</class>
<class>com.sensorhound.common.domain.impl.NodeAlert</class>
<class>com.sensorhound.common.domain.impl.NodeRule</class>
<class>com.sensorhound.common.domain.impl.NodeRuleDefinition</class>
<class>com.sensorhound.common.domain.impl.Organization</class>
<class>com.sensorhound.common.domain.impl.PastGroupStatus</class>
<class>com.sensorhound.common.domain.impl.Trace</class>
<class>com.sensorhound.common.domain.impl.TrainingSession</class>
<class>com.sensorhound.common.domain.impl.User</class>
<class>com.sensorhound.common.domain.impl.Role</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.show_sql" value = "false" />
<property name="hibernate.connection.autocommit" value="true" />
<property name="hibernate.event.merge.entity_copy_observer" value="allow"/>
<property name="transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory"/>
<property name="jta.UserTransaction" value="java:jboss/UserTransaction"/>
</properties>
</persistence-unit>
</persistence>
我有一个这样的端点:
@Path("/delete")
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON)
public Response deleteUser(@FormParam("organization_id") Integer organizationId,
@FormParam("username") String username) throws JsonProcessingException, NotSupportedException,
SystemException, SecurityException, IllegalStateException, RollbackException,
HeuristicMixedException, HeuristicRollbackException, NamingException {
Organization org = organizationDAO.getByOrganizationId(organizationId);
userDao.deleteUserByUserNameAndOrganization(username, org);
return Response.status(Response.Status.OK).build();
}
DAO 是这样的:
public class userDAO {
@PersistenceContext(unitName = "SensorCloudPU")
protected EntityManager em;
@Resource
protected UserTransaction utx;
public void deleteUserByUserNameAndOrganization(String userName, Organization org)
throws NotSupportedException, SystemException, SecurityException, IllegalStateException,
RollbackException, HeuristicMixedException, HeuristicRollbackException {
Query q = this.em.createNamedQuery(User.Q_GET_BY_USERNAME_AND_ORGANIZATION);
q.setParameter("organization", org);
q.setParameter("user_name", userName);
User u = this.executeQueryForSingleResult(q);
if (u == null) {
return;
}
utx.begin();
this.em.remove(u);
utx.commit();
}
}
但是每次加载页面并尝试从数据库中删除时,我都会收到此错误:
注入资源查找失败:java:jboss/UserTransaction]
UserTransaction [根异常是 java.lang.IllegalStateException:WFLYEJB0137:只允许具有 bean 管理的事务划分的会话和消息驱动的 bean 访问 UserTransaction]
您不能在 EJB 中使用 UserTransaction,除非您添加 @TransactionManagement(BEAN)
TransactionManagement 所做的是
指定会话 bean 或消息驱动的 bean 是否具有容器管理的事务或 bean 管理的事务。如果不使用此注释,则假定该 bean 具有容器管理的事务管理。
@TransactionManagement(BEAN)
public class userDAO {
由于您主要关注事务管理,因此我建议您将 DAO 转换为 EJB。只需要一行:
@Stateless
public class userDAO {
@PersistenceContext(unitName = "SensorCloudPU")
protected EntityManager em;
public void deleteUserByUserNameAndOrganization(String userName, Organization org) {
Query q = this.em.createNamedQuery(User.Q_GET_BY_USERNAME_AND_ORGANIZATION);
q.setParameter("organization", org);
q.setParameter("user_name", userName);
User u = this.executeQueryForSingleResult(q);
if (u != null) {
this.em.remove(u);
}
}
}
你可以看到它大大简化了事情。 EJB 免费为您提供 JTA 事务划分(如果需要还可以回滚)。
即使您正在构建仅 WAR 的部署,这也会起作用。
如果需要,您还可以将 @Stateless
添加到您的 JAX-RS 端点。至少你会得到比其他方式更多的监控。
我有一个用于管理用户信息的 mySQL 数据库,我的 mySQL 数据库使用 JTA 数据源,下面是 persistence.xml 的样子:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="SensorCloudPU" transaction-type="JTA">
<jta-data-source>java:/SensorCloudPU</jta-data-source>
<!-- <non-jta-data-source>java:/SensorCloudPU</non-jta-data-source> -->
<class>com.sensorhound.common.domain.impl.AnomalousInfo</class>
<class>com.sensorhound.common.domain.impl.Code</class>
<class>com.sensorhound.common.domain.impl.Device</class>
<class>com.sensorhound.common.domain.impl.Executable</class>
<class>com.sensorhound.common.domain.impl.Group</class>
<class>com.sensorhound.common.domain.impl.GroupAlert</class>
<class>com.sensorhound.common.domain.impl.GroupRule</class>
<class>com.sensorhound.common.domain.impl.GroupRuleDefinition</class>
<class>com.sensorhound.common.domain.impl.GroupRuleStatus</class>
<class>com.sensorhound.common.domain.impl.Node</class>
<class>com.sensorhound.common.domain.impl.NodeAlert</class>
<class>com.sensorhound.common.domain.impl.NodeRule</class>
<class>com.sensorhound.common.domain.impl.NodeRuleDefinition</class>
<class>com.sensorhound.common.domain.impl.Organization</class>
<class>com.sensorhound.common.domain.impl.PastGroupStatus</class>
<class>com.sensorhound.common.domain.impl.Trace</class>
<class>com.sensorhound.common.domain.impl.TrainingSession</class>
<class>com.sensorhound.common.domain.impl.User</class>
<class>com.sensorhound.common.domain.impl.Role</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.show_sql" value = "false" />
<property name="hibernate.connection.autocommit" value="true" />
<property name="hibernate.event.merge.entity_copy_observer" value="allow"/>
<property name="transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory"/>
<property name="jta.UserTransaction" value="java:jboss/UserTransaction"/>
</properties>
</persistence-unit>
</persistence>
我有一个这样的端点:
@Path("/delete")
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON)
public Response deleteUser(@FormParam("organization_id") Integer organizationId,
@FormParam("username") String username) throws JsonProcessingException, NotSupportedException,
SystemException, SecurityException, IllegalStateException, RollbackException,
HeuristicMixedException, HeuristicRollbackException, NamingException {
Organization org = organizationDAO.getByOrganizationId(organizationId);
userDao.deleteUserByUserNameAndOrganization(username, org);
return Response.status(Response.Status.OK).build();
}
DAO 是这样的:
public class userDAO {
@PersistenceContext(unitName = "SensorCloudPU")
protected EntityManager em;
@Resource
protected UserTransaction utx;
public void deleteUserByUserNameAndOrganization(String userName, Organization org)
throws NotSupportedException, SystemException, SecurityException, IllegalStateException,
RollbackException, HeuristicMixedException, HeuristicRollbackException {
Query q = this.em.createNamedQuery(User.Q_GET_BY_USERNAME_AND_ORGANIZATION);
q.setParameter("organization", org);
q.setParameter("user_name", userName);
User u = this.executeQueryForSingleResult(q);
if (u == null) {
return;
}
utx.begin();
this.em.remove(u);
utx.commit();
}
}
但是每次加载页面并尝试从数据库中删除时,我都会收到此错误:
注入资源查找失败:java:jboss/UserTransaction]
UserTransaction [根异常是 java.lang.IllegalStateException:WFLYEJB0137:只允许具有 bean 管理的事务划分的会话和消息驱动的 bean 访问 UserTransaction]
您不能在 EJB 中使用 UserTransaction,除非您添加 @TransactionManagement(BEAN)
TransactionManagement 所做的是
指定会话 bean 或消息驱动的 bean 是否具有容器管理的事务或 bean 管理的事务。如果不使用此注释,则假定该 bean 具有容器管理的事务管理。
@TransactionManagement(BEAN)
public class userDAO {
由于您主要关注事务管理,因此我建议您将 DAO 转换为 EJB。只需要一行:
@Stateless
public class userDAO {
@PersistenceContext(unitName = "SensorCloudPU")
protected EntityManager em;
public void deleteUserByUserNameAndOrganization(String userName, Organization org) {
Query q = this.em.createNamedQuery(User.Q_GET_BY_USERNAME_AND_ORGANIZATION);
q.setParameter("organization", org);
q.setParameter("user_name", userName);
User u = this.executeQueryForSingleResult(q);
if (u != null) {
this.em.remove(u);
}
}
}
你可以看到它大大简化了事情。 EJB 免费为您提供 JTA 事务划分(如果需要还可以回滚)。
即使您正在构建仅 WAR 的部署,这也会起作用。
如果需要,您还可以将 @Stateless
添加到您的 JAX-RS 端点。至少你会得到比其他方式更多的监控。