【发布时间】:2018-08-22 08:09:13
【问题描述】:
对于我们使用 Hibernate 的项目,我们有一个每个表模式一个 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+"%");
}
}
}
【问题讨论】:
标签: java sql-server hibernate spring-mvc