Обычная версия
Java форум JavaTalks
форум программистов

Поиск   Пользователи   Группы   Регистрация 
 Профиль   Личные сообщения 

 Вход 

Транзакции с JdbcTemplate
Список форумов
 ->  Java Enterprise и распределённые технологии


 
Начать новую тему 
Предыдущая тема :: Следующая тема  
Автор Сообщение
shoo : 115
Новичок

СообщениеЯнв 26, 2012 14:48 
Ответить с цитатой
Делаю jdbcTemplate.update(), а затем, на основе KeyHolder, делаю jdbcTemplate.update другой таблицы. Всё в одном методе. Мне нужно сделать так, чтобы если что-то вызвало ошибку, то метод бы совсем ничего не делал с БД. Как это сделать?
К началу Посмотреть профиль Отправить личное сообщение
shoo : 115
Новичок

СообщениеЯнв 26, 2012 15:23 
Ответить с цитатой
Указываю перед методом
Код:
@Transactional(propagation = Propagation.REQUIRED)

Но никакой реакции. После первого update у меня вызывается исключение, но он всё-равно записывает в таблицу данные.
К началу Посмотреть профиль Отправить личное сообщение
tender_swallow : 472
Бывалый
Откуда: Ivanovo

СообщениеЯнв 26, 2012 15:47 
Ответить с цитатой
А вы менеджер транзакци для JDBC настроили?
Код:

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <property name="dataSource" ref="dataSource"/>
</bean


И так как Вы декларативно управляете транзакциями через аннотации, то нужно указать такой элемент к контексте <tx:annotation-driven>.
К началу Посмотреть профиль Отправить личное сообщение Посетить сайт автора
shoo : 115
Новичок

СообщениеЯнв 26, 2012 16:35 
Ответить с цитатой
Ага, лол. Я нашёл это в документации и вожусь с этим почти час.
<tx:annotation-driven> не хочет подключаться по умолчанию. Похоже, он требует библиотеки.
Я подключил:
Код:

lib\aopalliance.jar
lib\asm-4.0.jar
lib\cglib-2.1_3.jar

Но только это не очень помогло. Постоянно вылетает:
java.lang.NoClassDefFoundError: Could not initialize class net.sf.cglib.proxy.Enhancer

Странно потому, что я попробовал и 2.2 и 2.2.2 cglib. Не знаете, случайно, какие точно библиотеки нужны для подключения tx?
К началу Посмотреть профиль Отправить личное сообщение
tender_swallow : 472
Бывалый
Откуда: Ivanovo

СообщениеЯнв 26, 2012 16:50 
Ответить с цитатой
3-ий Спринг? Вот тут по этой проблеме написано какие библиотеки подключить http://blog.newsplore.com/2009/03/07/upgrading-to-spring-30.

Сам работаю на 2.5 версии, там с таким не сталкивался.
К началу Посмотреть профиль Отправить личное сообщение Посетить сайт автора
shoo : 115
Новичок

СообщениеЯнв 26, 2012 18:56 
Ответить с цитатой
В итоге, с asm-3.3 и cglib-2.2 всё заработало. Точнее, аннотация воспринялась, но вот транзакции так и не стали работать. Впрочем, у меня не было времени особенно посмотреть в чём дело, так что завтра продолжу.

Значит, алгоритм такой:
Подключаем <tx:annotation-driven/>
Необходимому методу указываем @Transactional(propagation = Propagation.REQUIRED)
Если метод работает с JdbcTemplate, то все запросы работают в районе одной транзакции, так?

Возможно, у меня происходит запись в БД по той причине, что между запросами посылается Exception и, соответственно, выполнив первый запрос, блок try прерывается и второй запрос просто не создаётся. Поэтому, Spring решает, что всё ОК, т.к. закончилось всё не ошибкой работы с БД и, соответственно коммитит транзакцию.

Надо бы получше изучить документацию.
К началу Посмотреть профиль Отправить личное сообщение
mesier : 693
Постоянный посетитель
Откуда: Новокузнецк

СообщениеЯнв 27, 2012 6:16 
Ответить с цитатой
shoo писал(а):
Значит, алгоритм такой:
Подключаем <tx:annotation-driven/>
Необходимому методу указываем @Transactional(propagation = Propagation.REQUIRED)
Если метод работает с JdbcTemplate, то все запросы работают в районе одной транзакции, так?

Ну да, так должно быть..

shoo писал(а):
Возможно, у меня происходит запись в БД по той причине, что между запросами посылается Exception и, соответственно, выполнив первый запрос, блок try прерывается и второй запрос просто не создаётся. Поэтому, Spring решает, что всё ОК, т.к. закончилось всё не ошибкой работы с БД и, соответственно коммитит транзакцию. Надо бы получше изучить документацию.

А какой эксепшн?
Есть у меня подозрения, что транзакции будут откатываться только при выбросе SqlException..
А других вообще-то эксепшенов в методе ДАО и не должно бы быть по идее. ДАО на то он и ДАО, что обязан только принеси-подай между прогой и источником данных выполнять. Если там что-то другое, да ещё небезопасное, это ошибка проектирования..

Логику пре- и пост-обработки резалтсета следует помещать в сервис-классы.
Ваш Кэп.
Smile
К началу Посмотреть профиль Отправить личное сообщение ICQ Number
shoo : 115
Новичок

СообщениеЯнв 27, 2012 9:01 
Ответить с цитатой
У меня всё гораздо хуже ._.
Нет никаких ДАО классов, а всё работает через сервис. Контроллеру нужна информация из БД - он обратился к сервису и получил инфу. Ну ещё POJO есть, для хранения информации и всё. По крайней мере, начинать с такого было проще.

Сейчас попробовал добавить SQLException, ни чем не помогло. Всё так же, одна запись добавляется, а другая - нет. Попробовал "сломать" второй запрос. Тоже ничего.

Блин.
К началу Посмотреть профиль Отправить личное сообщение
shoo : 115
Новичок

СообщениеЯнв 27, 2012 9:58 
Ответить с цитатой
Попытался разобраться с ДАО. Вот что получилось:
У меня есть таблица messages и таблица pictures. Соответственно, каждому сообщению по изображению. Хранятся в разных таблицах только потому, что далее хочу сделать несколько изображений получается на сообщение.

В итоге:
а) Делаю модель Message, в котором есть id, author, text, prev_id, picture_id.
б) Делаю на каждую таблицу различные ДАО реализации.
в) В сервисе использую обе ДАО реализации для заполнения модели Message, т.е., например:
Код:

added_message_id = MessageDAOImpl.add("John","Hellow, world!", 0);
PictureDAOImpl.add(added_message.id); // return picture id
// то есть, добавляется новое сообщение и картинка, выдаётся id, чтобы кинуть изображение затем в статическую папку под выданным номером.


Так как мы помечаем методы DAO как @Transactional, то получится, что в одной транзакции выполняется:
MessageDAOImpl.add("John","Hellow, world!", 0);
В другой:
PictureDAOImpl.add(added_message.id);

Всё правильно описал?
К началу Посмотреть профиль Отправить личное сообщение
shoo : 115
Новичок

СообщениеЯнв 27, 2012 15:25 
Ответить с цитатой
Ура! Сделал всё с DAO и нормально работает.
К началу Посмотреть профиль Отправить личное сообщение
mesier : 693
Постоянный посетитель
Откуда: Новокузнецк

СообщениеЯнв 27, 2012 15:55 
Ответить с цитатой
shoo писал(а):
Ура! Сделал всё с DAO и нормально работает.

И как же сделал?
К началу Посмотреть профиль Отправить личное сообщение ICQ Number
shoo : 115
Новичок

СообщениеЯнв 27, 2012 17:43 
Ответить с цитатой
mesier писал(а):

И как же сделал?

Вот такое вот чудовище получилось:
Код:
public class Message {
    private Integer id;
    private Date date;
    private String author;
    private String text;
    private Integer prev_id;
// get n set
}


Код:
public class Picture {
    private Integer id;
    private Integer message_id;
// get n set
}


Код:
@Repository("messageDAOImpl")
public class MessageDAOImpl implements MessageDAO {

    private JdbcTemplate jdbcTemplate;
   
    @Resource(name="testDataSource")
    public void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
   
    @Transactional
    @Override
    public Integer create(String author, String text, Integer prevId) {
        Message addedMessage = new Message();
        addedMessage.setAuthor(author);
        addedMessage.setText(text);
        addedMessage.setPrev_id(prevId);
       
        final Message finalMessage = addedMessage;
        final String sql = "INSERT INTO `messages` (`author`, `text`, `prev_id`) VALUES (?,?,?)";
       
        KeyHolder keyHolder = new GeneratedKeyHolder();
       
        jdbcTemplate.update(
                new PreparedStatementCreator() {
                    @Override
                    public PreparedStatement createPreparedStatement(Connection cnctn) throws SQLException {
                            PreparedStatement ps = cnctn.prepareStatement(
                                sql,
                                new String[] {"id"});
                            ps.setString(1, finalMessage.getAuthor());
                            ps.setString(2, finalMessage.getText());
                            ps.setInt(3, finalMessage.getPrev_id());
                            return ps;                       
                    }                   
                }
                , keyHolder);   
       
        return keyHolder.getKey().intValue();
    }
   
}


Код:
@Repository("pictureDAOImpl")
public class PictureDAOImpl implements PictureDAO{

    private JdbcTemplate jdbcTemplate;
   
    @Resource(name="testDataSource")
    public void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
   
    @Transactional
    @Override
    public Integer create(Integer message_id) {
        final String sql_picture = "INSERT INTO `pictures` (`message_id`) VALUES (?)";
        final Integer finalMessageId = message_id;
       
        KeyHolder keyHolder = new GeneratedKeyHolder();
       
        jdbcTemplate.update(
                new PreparedStatementCreator() {
                    @Override
                    public PreparedStatement createPreparedStatement(Connection cnctn) throws SQLException {
                            PreparedStatement ps = cnctn.prepareStatement(
                                sql_picture,
                                new String[] {"id"});
                            ps.setInt(1, finalMessageId);
                            return ps;
                    }                   
                }
                , keyHolder);
       
        return keyHolder.getKey().intValue();
    }

    @Override
    public Integer get(Integer id) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
   
}

Код:

@Service("messageService")
public class MessageService {
   
    @Resource(name = "messageDAOImpl")
    private MessageDAO messageDAO;

    @Resource(name = "pictureDAOImpl")
    private PictureDAO pictureDAO;
   
    @Transactional(propagation = Propagation.REQUIRED)
    public void newMessage(String author, String text, Integer prevId) {
        try {
            System.out.println(messageDAO.create(author, text, prevId));
            System.out.println(pictureDAO.create(0));
        } catch(Exception e) {
            System.out.println("Error.");
        }
    }
   
}
К началу Посмотреть профиль Отправить личное сообщение
shoo : 115
Новичок

СообщениеЯнв 27, 2012 17:49 
Ответить с цитатой
Мне интересно, правильно ли я понял суть DAO и сервисов. Подскажите?
Правда, метод newMessage сервиса ещё не доработан и 0 там выставлен, чтобы проверить транзакцию(такого сообщения не существует, а таблицы связанны при помощи foreign key).

Я делал из расчёта на то, что интерфейс DAO описывает действия с БД для отдельно взятой таблицы, а точнее такие действия как create, read, update, delete. Реализация DAO реализует работу этого интерфейса, в данном случае при помощи JdbcTemplate. Сервис уже получает то, что нужно контроллеру при помощи методов DAO, попутно реагируя на исключения.
К началу Посмотреть профиль Отправить личное сообщение
shoo : 115
Новичок

СообщениеЯнв 28, 2012 10:45 
Ответить с цитатой
Вот, кстати, что мне ответили на SF форуме по этому вопросу:
Цитата:
For starters you ode is flawed NEVER catch the exception and swallow. The transaction management needs to see the exception else rollbacks don't happen, the same for the PreparedStatementCreator (which I wonder why are you using that ?!)
К началу Посмотреть профиль Отправить личное сообщение
Vermut : 1062
Завсегдатай
Откуда: Ростов-на-Дону

СообщениеЯнв 29, 2012 10:15 
Ответить с цитатой
Ты можешь убрать аннотацию Transactional с методов ДАО, потому что транзакция уже открывается при вызове метода сервиса.
_________________
Познакомлюсь с привлекательной Ростовчанкой для совместного изучения Java
К началу Посмотреть профиль Отправить личное сообщение Отправить e-mail
 
Начать новую тему  Ответить на тему
Страница 1 из 1
Список форумов
 -> Java Enterprise и распределённые технологии


 
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах


Java and all Java-related trademarks and logos are trademarks or registered trademarks of Oracle Corporation in the United States and other countries.
Это сайт не относится к фирме Oracle Corporation и не поддерживается ею.

© 2006-2010 www.javatalks.ru: форум java программистов
Используется скрипт phpBB © 2001, 2010 phpBB Group

Хостинг от bizname.ru