Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Hibernate,在一个事务中修改多个表的正确方法_Java_Sql Server_Hibernate_Spring Mvc - Fatal编程技术网

Java Hibernate,在一个事务中修改多个表的正确方法

Java Hibernate,在一个事务中修改多个表的正确方法,java,sql-server,hibernate,spring-mvc,Java,Sql Server,Hibernate,Spring Mvc,对于使用Hibernate的项目,每个表有一个DAO模式。在每个DAO调用中,我们创建一个事务,并在它完成执行后提交 现在,我们需要更新同一事务中的两个表。这种情况很常见,我们需要发出销售支票,然后从库存中减少出售物品的数量。当然,这些都必须在同一个事务中完成 所以,我的问题是,在一个事务中修改多个表的正确方法是什么。这是我们刀的一个例子。如您所见,每个DAO仅用于处理一个表 我们既没有实现计费,也没有实现库存DAO。我们想知道哪一种是实现我们需求的正确方式。任何帮助都会很好 @Service

对于使用Hibernate的项目,每个表有一个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+"%");
    }
}
}
@服务
公共类StoreDao实现实现了StoreDao{
//我们将为每个数据访问对象(dao)使用每请求会话模式。
//为了使用它,我们需要一个会话工厂,为每个请求提供会话。
私营工厂;
公共存储实现(){
试一试{
工厂=新配置().configure().buildSessionFactory();
}捕获(例外e){
e、 printStackTrace();
}
}
/**
*{@inheritardoc}
*/
@凌驾
公共Tienda findById(字符串存储ID){
Session Session=factory.getCurrentSession();
事务tx=会话.beginTransaction();
试一试{
return session.get(Tienda.class,storeId);
}捕获(例外e){
返回null;
}最后{
tx.commit();
}
}
/**
*{@inheritardoc}
*/
@凌驾
公共无效插入(Tienda Tienda)引发异常{
Session Session=factory.getCurrentSession();
事务tx=会话.beginTransaction();
会议.坚持(蒂恩达);
tx.commit();
}
/**
*{@inheritardoc}
*/
@凌驾
公共无效删除(Tienda Tienda)引发异常{
Session Session=factory.getCurrentSession();
事务tx=会话.beginTransaction();
删除(tienda);
tx.commit();
}
/**
*{@inheritardoc}
*/
@凌驾
公共无效更新(Tienda Tienda)引发异常{
Session Session=factory.getCurrentSession();
事务tx=会话.beginTransaction();
合并会议(tienda);
tx.commit();
}
/**
*{@inheritardoc}
*/
@凌驾
public void updateSupervisor(列表存储ID、字符串监管者ID)引发异常{
Session Session=factory.getCurrentSession();
事务tx=会话.beginTransaction();
Query Query=session.createQuery(“UPDATE Tienda SET supervisor.idEmpleadoPk=:supervisorId,其中idTiendaPk位于(:storeIds)”);
query.setParameter(“supervisorId”,supervisorId);
setParameter(“storeId”,storeId);
query.executeUpdate();
tx.commit();
}
/**
*{@inheritardoc}
*/
@凌驾
公共列表getAllStores(整数偏移,
整数行数,
字符串特许权,
弦国,
布尔状态,
字符串storeName,
整数orderBy,
整数(订单类型){
//始终使用getCurrentSession,而不是openSession。
//只有在非常奇怪的情况下,如果使用后者,那么我们必须记住结束我们的会议。
//有关更多信息,请阅读以下文档。
// http://docs.jboss.org/hibernate/core/3.3/reference/en/html/transactions.html#transactions-基础uow
Session Session=factory.getCurrentSession();
//所有hibernate事务必须在活动事务中执行。
事务tx=会话.beginTransaction();
试一试{
setSessionFilter(会话、特许经营、国家、州、店名);
//注意:在这个查询中,我使用的是join fetch。这是由于一个Hibernate错误造成的,这是不允许的
//在映射文件中设置获取类型。这样做的目的是代替多次选择
//对于每个连接,它只是在主查询中执行一个大连接。
//如果使用远程服务器,速度会更快。
String hql=“from Tienda T join fetch T.supervisor join fetch T.franquiciaFK join fetch T.pais”;
开关((orderBy!=null)?orderBy:4){
案例0:
hql+=“T.franquiciaFK.franquiciaPk的订单”;
打破
案例1:
hql+=“按T.pais.paisPk订购”;
打破
案例2:
hql+=“T.provincia的订单”;
打破
案例3:
hql+=“T.supervisor.idempeadopk下的订单”;
打破
违约:
hql+=“T.franquiciaFK.orden的订单”;
打破
}
开关((orderType!=null)?orderType:0){
案例0:
hql+=“asc”;
打破
案例1:
hql+=“描述”;
打破
}
Query=session.createQuery(hql);
query.setFirstResult(偏移量);
query.setMaxResults(rowNumber-1);
返回query.list();
}捕获(例外e){
返回null;
}最后{
tx.commit();
}
}
/**
*{@inheritardoc}
*/
@凌驾
公共列表getStoresBySupervisor(字符串supervisorId){
Session Session=factory.getCurrentSession();
事务tx=会话.beginTransaction();
试一试{
//注意:在这个查询中,我使用的是join fetch。这是由于一个Hibernate错误造成的,这是不允许的
//在映射文件中设置获取类型。这样做的目的是代替多次选择
//对于每个连接,它只是在主查询中执行一个大连接。
//如果使用远程服务器,速度会更快。
Query Query=session.createQuery(“从Tienda T join获取T.supervisor join
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;
    }
}