- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
对于一个使用 Hibernate 的项目,我们有一个 DAO 每表模式。在每个 DAO 调用中,我们创建一个事务并在执行完成后提交。
现在,我们需要在同一事务中更新两个表。这种情况很常见,我们需要发出销售支票,然后减少库存中销售的元素数量。当然,这一切都必须在同一个事务中完成。
所以,我的问题是,这是在一个事务中修改多个表的正确方法。这是我们 DAO 之一的示例。正如您所看到的,每个 DAO 仅用于处理一张表。
我们尚未实现计费 DAO 或库存 DAO。我们想知道哪种方法是满足我们需求的正确方法。任何帮助都会很棒。
@Service
public class StoreDaoImplementation implements StoreDao {
// We are gonna use a session-per-request pattern, for each data access object (dao).
// In order to use it, we need an session factory that will provide us with sessions for each request.
private SessionFactory factory;
public StoreDaoImplementation() {
try{
factory = new Configuration().configure().buildSessionFactory();
}catch(Exception e){
e.printStackTrace();
}
}
/**
* {@inheritDoc}
*/
@Override
public Tienda findById(String storeId) {
Session session = factory.getCurrentSession();
Transaction tx = session.beginTransaction();
try {
return session.get(Tienda.class, storeId);
} catch (Exception e) {
return null;
} finally {
tx.commit();
}
}
/**
* {@inheritDoc}
*/
@Override
public void insert(Tienda tienda) throws Exception {
Session session = factory.getCurrentSession();
Transaction tx = session.beginTransaction();
session.persist(tienda);
tx.commit();
}
/**
* {@inheritDoc}
*/
@Override
public void delete(Tienda tienda) throws Exception {
Session session = factory.getCurrentSession();
Transaction tx = session.beginTransaction();
session.delete(tienda);
tx.commit();
}
/**
* {@inheritDoc}
*/
@Override
public void update(Tienda tienda) throws Exception {
Session session = factory.getCurrentSession();
Transaction tx = session.beginTransaction();
session.merge(tienda);
tx.commit();
}
/**
* {@inheritDoc}
*/
@Override
public void updateSupervisor(List<String> storeIds, String supervisorId) throws Exception {
Session session = factory.getCurrentSession();
Transaction tx = session.beginTransaction();
Query query = session.createQuery("UPDATE Tienda SET supervisor.idEmpleadoPk = :supervisorId WHERE idTiendaPk IN (:storeIds)");
query.setParameter("supervisorId", supervisorId);
query.setParameter("storeIds", storeIds);
query.executeUpdate();
tx.commit();
}
/**
* {@inheritDoc}
*/
@Override
public List<Tienda> getAllStores(Integer offset,
Integer rowNumber,
String franchise,
String country,
Boolean state,
String storeName,
Integer orderBy,
Integer orderType) {
// Always use getCurrentSession, instead of openSession.
// Only in very odd cases, should the latter be used, then we must remember to close our session.
// For more information, read the following docs.
// http://docs.jboss.org/hibernate/core/3.3/reference/en/html/transactions.html#transactions-basics-uow
Session session = factory.getCurrentSession();
// All hibernate transactions must be executed in an active transaction.
Transaction tx = session.beginTransaction();
try {
setSessionFilter(session, franchise, country, state, storeName);
// NOTE: In this query I am using join fetch. This is due a Hibernate bug, that won't allow
// setting the fetch type in the mapping file. What this does, is that instead of doing multiple selects
// for each join, it just simply does a big join in the main query.
// Much faster if you are working with a remote server.
String hql = "from Tienda T join fetch T.supervisor join fetch T.franquiciaFK join fetch T.pais";
switch ((orderBy != null) ? orderBy : 4) {
case 0:
hql += " order by T.franquiciaFK.franquiciaPk";
break;
case 1:
hql += " order by T.pais.paisPk";
break;
case 2:
hql += " order by T.provincia";
break;
case 3:
hql += " order by T.supervisor.idEmpleadoPk";
break;
default:
hql += " order by T.franquiciaFK.orden";
break;
}
switch ((orderType != null) ? orderType : 0) {
case 0:
hql += " asc";
break;
case 1:
hql += " desc";
break;
}
Query query = session.createQuery(hql);
query.setFirstResult(offset);
query.setMaxResults(rowNumber-1);
return query.list();
} catch (Exception e) {
return null;
} finally {
tx.commit();
}
}
/**
* {@inheritDoc}
*/
@Override
public List<Tienda> getStoresBySupervisor(String supervisorId) {
Session session = factory.getCurrentSession();
Transaction tx = session.beginTransaction();
try {
// NOTE: In this query I am using join fetch. This is due a Hibernate bug, that won't allow
// setting the fetch type in the mapping file. What this does, is that instead of doing multiple selects
// for each join, it just simply does a big join in the main query.
// Much faster if you are working with a remote server.
Query query = session.createQuery("from Tienda T join fetch T.supervisor join fetch T.franquiciaFK join fetch T.pais where T.supervisor.idEmpleadoPk = :supervisorId");
query.setParameter("supervisorId", supervisorId);
return query.list();
} catch (Exception e) {
return null;
} finally {
tx.commit();
}
}
/**
* {@inheritDoc}
*/
@Override
public Integer countAllStores(String franchise, String country, Boolean state, String storeName) {
Session session = factory.getCurrentSession();
Transaction tx = session.beginTransaction();
try {
// Check that the filters are not null.
setSessionFilter(session, franchise, country, state, storeName);
Query query = session.createQuery("select count(*) from Tienda");
return ((Long) query.iterate().next()).intValue();
} catch (Exception e) {
return null;
} finally {
tx.commit();
}
}
/**
* Given that we already know the all filters we can use in our stores' queries,
* we can make a method to configure them.
* @param session Actual session that will query the DB.
* @param franchise Franchise filter. Only returns those store of the specified franchise.
* @param country Country filter. Only returns those store of the specified country.
* @param state State filter. Only returns those stores of the specified state.
*/
private void setSessionFilter(Session session, String franchise, String country, Boolean state, String name) {
if(franchise != null && !franchise.isEmpty()) {
session.enableFilter("storeFranchiseFilter").setParameter("franchiseFilter", franchise);
}
if(country != null && !country.isEmpty()) {
session.enableFilter("storeCountryFilter").setParameter("countryFilter", country);
}
if(state != null) {
session.enableFilter("storeStateFilter").setParameter("stateFilter", state);
}
if(name != null && !name.isEmpty()) {
session.enableFilter("storeNameFilter").setParameter("nameFilter", "%"+name+"%");
}
}
}
最佳答案
您可以使用Transactional
注释,它提供了更多控制,例如异常回滚以及处理多个事务。
public interface BillingService {
public BillingDAO getBalance();
}
@Service(value = "billingService")
@Transactional("transactionManager")
public class BillingServiceImpl implements BillingService {
@Autowired
private SessionFactory sessionFactory;
@Override
// Transactional // you can have method level transaction manager, which can be different from one method to another
public BillingDAO getBalance(long id) {
return sessionFactory.getCurrentSession().get(BillingDAO.class, id);
}
}
public interface StockService {
public StockDAO getStock();
}
@Service(value = "stockService")
@Transactional("transactionManager")
public class StockServiceImpl implements StockService {
@Autowired
private SessionFactory sessionFactory;
@Autowired
private BillingService billingService;
@Override
// Transactional
public StockDAO getStock(long id) {
// if you want to use billing related changes, use billing server which is autowired
BillingDAO billingDAO = billingService.getBalance(id);
return sessionFactory.getCurrentSession().get(StockDAO.class, billingDAO.getStockId());
}
}
@Configuration
@EnableTransactionManagement
public class DatabaseConfig {
@Autowired
private ApplicationContext appContext;
@Autowired
private ApplicationProperties applicationProperties;
@Bean
public HikariDataSource getDataSource() {
HikariDataSource dataSource = new HikariDataSource();
dataSource
.setDataSourceClassName(applicationProperties.getHibernateDatasource());
dataSource.addDataSourceProperty("databaseName", applicationProperties.getRdbmsDatabase());
dataSource.addDataSourceProperty("portNumber", applicationProperties.getRdbmsPort());
dataSource.addDataSourceProperty("serverName", applicationProperties.getRdbmsServer());
dataSource.addDataSourceProperty("user", applicationProperties.getRdbmsUser());
dataSource.addDataSourceProperty("password", applicationProperties.getRdbmsPassword());
return dataSource;
}
@Bean("transactionManager")
public HibernateTransactionManager transactionManager() {
HibernateTransactionManager manager = new HibernateTransactionManager();
manager.setSessionFactory(hibernate5SessionFactoryBean().getObject());
return manager;
}
@Bean(name = "sessionFactory")
public LocalSessionFactoryBean hibernate5SessionFactoryBean() {
LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
localSessionFactoryBean.setDataSource(appContext
.getBean(HikariDataSource.class));
localSessionFactoryBean.setAnnotatedClasses(BillingDAO.class);
Properties properties = new Properties();
// properties.put("hibernate.current_session_context_class","thread");
// // because I am using Spring, it will take care of session context
/*
*
* Spring will by default set its own CurrentSessionContext
* implementation (the SpringSessionContext), however if you set it
* yourself this will not be the case. Basically breaking proper
* transaction integration.
*
* Ref:
* https://stackoverflow.com/questions/18832889/spring-transactions-and-hibernate-current-session-context-class
*/
properties.put("hibernate.dialect",
applicationProperties.getHibernateDialect());
properties.put("hibernate.hbm2ddl.auto", applicationProperties.getHibernateHbm2ddlAuto());
properties.put("hibernate.show_sql", applicationProperties.getShowSql());
// properties.put("hibernate.hbm2ddl.import_files",
// "/resource/default_data.sql"); // this will execute only
// when hbm2ddl.auto is set to "create" or "create-drop"
// properties.put("connection.autocommit", "true");
localSessionFactoryBean.setHibernateProperties(properties);
return localSessionFactoryBean;
}
}
关于java - Hibernate,在一个事务中修改多个表的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49266852/
什么是 hibernate 和n- hibernate ?我可以在 Visual Studio 2008 中使用它进行 C# Web 应用程序开发吗?请给我建议...我是 asp.net Web 应用
我有一个不系统地发生的异常(exception)。 我试图通过在每次迭代中刷新和清理 session 来解决此问题,但没有成功。 [quartzScheduler_Worker-7] ERROR jd
使用 Hibernate 在数据库中存储 IP 地址的最佳类型是什么? 我虽然是 Byte[] 或 String,但有没有更好的方法,或者你用什么? @Column(name = "range_fr
我正在尝试制定一个公式来选择用户个人资料的用户友好名称。它选择名字 + ' ' + 姓氏 如果其中至少有一个不为空且不为空(包含非空白字符),否则选择 短名称 (条件相同),最后,如果 短名称 为空或
在hibernate中,是否可以将鉴别器作为一个实体?例如,如果我将 Department 作为基类,将 AdminDepartment 和 ProcessingDepartment 作为子类。 De
我只想从表中获取一些列值。因此,我已经使用投影来实现这一目标。该代码有效,但我认为它无效。 我的问题是当我使用ProjectionsList并将标准条件列表设置为ArrayList时-Bulletin
你好: 我对 hibernate 缓存缓存的内容感到困惑。 从文档中,我知道 hibernate 中有缓存类型。 一级 :交易级别。 似乎要被 session 持久化的实体被缓存在这里。 二级缓存 :
我遇到了一个情况: save或update hibernate 的目标表中的某些数据 在目标表上有一个触发器,该触发器将在目标表的insert或update操作之前执行 由 hibernate 将此记
我有一个名为 Master_Info_tbl 的表。它是一个查询表: 这是该表的代码: @Entity @Table(name="MASTER_INFO_T") public class Code
我想知道如何在 Hibernate 查询语言中使用日期文字。我在我的 JPA 项目中做了如下操作(作为 Eclipselink 提供者)并且它工作正常。 SELECT m FROM Me m WHER
@Entity public class Troop { @OneToMany(mappedBy="troop") public Set getSoldiers() { ...
我正在尝试使用 hibernate 查询删除表 'user_role' 中的所有行。但每次我都会出错。有人可以帮我吗。 DaoImpl @Override public void deleteAll(
不是将数据库操作分散在四个 (osgi) 包中,而是在那里做略有不同的事情。我想创建一个负责所有持久性问题的(简单的)OSGi 包。我觉得这并不像听起来那么简单,因为“每个包都有独特的类加载器”。 因
这就是我使用生成器的方式: private Integer id; 我看到的行为是: 创建第一个对象 hibernate 分配 id = 1 删除该对象 关闭服务
对象级别的实体和值类型有什么区别。我知道实体将有一个 id 但值不会,但为什么我们需要不同的方法来映射实体与值类型? 这样做是为了让hibernate可以对值类型应用任何优化吗? 最佳答案 一个实体已
我正在使用 HibernateTemplate.findByCriteria 方法进行一些查询。现在我想在标准上创建一些 SQL 限制,比如 criteria.add(Restrictions.sql
所以我有以下代码: Query query = session.createQuery("from Weather"); List list = query.list();
如何使用Hibernate映射具有多个实体的 View ? 问候, 混沌 最佳答案 请参见Hibernate文档中第5.1.3节“类”,紧接在“Id”节之前: There is no differen
据我所知,Hibernate 有两种类型的实现 JPA的实现(2)(@Entity,@Table注解) 扩展到旧的(传统的) hibernate (没有 JPA),使用 HSQL 查询,没有注释 如果
我需要一个将条目存储为键值对的集合(因此我可以通过键查找值),但我需要一个允许多个值使用 hibernate 共享同一个键的集合 最佳答案 一个键具有多个值的映射称为多映射 - 在 Apache 公共
我是一名优秀的程序员,十分优秀!