
[code]

    // DAO
    @Transactional
    public class UserDAO implements UserDAOInterface {
    
        @Inject
        EntityManager em;
    
        public User find(int id) {
            return em.find(User.class, id);
        }
    
        @Override
        public void update(User user) {
            // TODO Auto-generated method stub
            em.merge(user);
            em.flush();
        }
    
        // こちらは正常にトランザクション処理が実行（ロールバック）される
        public void transaction(User buyer, Item item) {
            User seller = find(item.getSellerId());
            int price = item.getPrice();
            buyer.setBalance(buyer.getBalance() - price);
            update(buyer);
            if(true) {
                throw new RuntimeException();
            }
            seller.setBalance(seller.getBalance() + price);
            update(seller);
        }
    
    }
    
[/code]

上記のDAOのtransactionメソッドを呼び出した場合は正常にロールバックされるのですが，

[code]

    // サービス層（ビジネスロジック）
    @Transactional
    public class UserLogic implements UserLogicInterface{
    
        UserDAOInterface dao = Guice.createInjector(new JpaPersistDaoModule())
                .getInstance(UserDAO.class);
    
        public User signIn(String email, String password) {
            return dao.find(email, password);
        }
    
        // こちらは正常に実行（ロールバック）されない
        public void transaction(User buyer, Item item) {
            User seller = dao.find(item.getSellerId());
            int price = item.getPrice();
            buyer.setBalance(buyer.getBalance() - price);
            dao.update(buyer);
            if(true) {
                throw new RuntimeException();
            }
            seller.setBalance(seller.getBalance() + price);
            dao.update(seller);
        }
    
    }
    
[/code]

こちら側のメソッドを呼び出した場合ではうまくいきませんでした（メソッドはコピー＆ペースト）．

実現したいのは後者のほうです（でないと，ビジネスロジックにEntityManagerを持たせかつそれをDAOのメソッドに引数として渡すという気持ちの悪いことをしなければなりません）．よろしくお願いします．

補足です．  
Google Guice と PostgresSQL を使用しています．


CC BY-SA 4.0
2018-08-19T08:01:23.277
47623
2018-08-21T10:50:55.293
2018-08-19T08:08:26.230
29776
29776
question
java-ee jpa
サービス層で宣言的トランザクションを扱いたい


問題があったのは以下のコードでした．

[code]

    // サービス層（ビジネスロジック）
    @Transactional
    public class UserLogic implements UserLogicInterface{
    
        UserDAOInterface dao = Guice.createInjector(new JpaPersistDaoModule())
                .getInstance(UserDAO.class);
    
        public User signIn(String email, String password) {
            return dao.find(email, password);
        }
    
        // こちらは正常に実行（ロールバック）されない
        public void transaction(User buyer, Item item) {
            User seller = dao.find(item.getSellerId());
            int price = item.getPrice();
            buyer.setBalance(buyer.getBalance() - price);
            dao.update(buyer);
            if(true) {
                throw new RuntimeException();
            }
            seller.setBalance(seller.getBalance() + price);
            dao.update(seller);
        }
    
    }
    
[/code]

このコードの

[code]

    UserDAOInterface dao = Guice.createInjector(new JpaPersistDaoModule())
                .getInstance(UserDAO.class);
    
[/code]

この部分です．ここを

[code]

    @Inject
    UserDAOInterface dao;
    
[/code]

と書き換えます．  
さらに，このクラスを生成するときに  
`new UserLogic();`  
とするのではなく，  
`UserLogic logic = Guice.createInjector(new
JpaPersistDaoModule()).getInstance(UserLogic.class);`  
とするのが正解だったみたいです．

お騒がせいたしました．


CC BY-SA 4.0
2018-08-21T10:50:55.293
47699
2018-08-21T10:50:55.293
29776
47623
answer