スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Spring MVC Spring Data JDBCを使って登録する

JPAを使ってテーブル更新処理を実装したので、今回はJDBCを使って、同様の処理を実装してみる。
なお、記載内容については、前々回のJPAとの差分をメインとする。

■前々回のJPAに関する記事
Spring MVC Spring Data JPAを使って登録する

■JDBCの過去の関連記事
Spring MVC Spring Data JDBCを使ってみる
Spring MVC Spring Data JDBCを使って検索する

◎動作検証にあたっての各バージョンは以下の通り
  • SpringFramework 3.2.8.RELEASE
  • Java 1.7
  • Tomcat 7.0

1.BookDao.java


package jp.co.sample.book.dao;

import java.util.List;

public interface BookDao<T> {

List<T> findAll();
List<T> findByNameLike(String name);
void addEntity(T entity);
}

BookDaoインターフェース。addEntityが今回実装する登録用メソッド。

2.BookDaoImpl.java


package jp.co.sample.book.dao;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import jp.co.sample.book.entity.BookEntity;

@Repository
public class BookDaoImplTemplate implements BookDao<BookEntity> {

private static Logger logger = LoggerFactory.getLogger(BookDaoImplTemplate.class);

@Autowired
private JdbcTemplate jdbcTemplate;

@Override
public List<BookEntity> findAll() {
logger.info("findAll start");
String sql = "SELECT * FROM Book";
List<BookEntity> entities = jdbcTemplate.query(sql, new RowMapper<BookEntity>() {
public BookEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
BookEntity entity = new BookEntity();
entity.setBookId(rs.getLong("book_id"));
entity.setBookName(rs.getString("book_name"));
entity.setPrice(rs.getInt("price"));
return entity;
}
});
return entities;
}

@Override
public List<BookEntity> findByNameLike(String name) {
logger.info("findByNameLike start");
String sql = "SELECT * FROM Book WHERE book_name LIKE '%'||?||'%'";
List<BookEntity> entities = jdbcTemplate.query(sql, new RowMapper<BookEntity>() {
public BookEntity mapRow(ResultSet rs, int rowNum) throws SQLException {
BookEntity entity = new BookEntity();
entity.setBookId(rs.getLong("book_id"));
entity.setBookName(rs.getString("book_name"));
entity.setPrice(rs.getInt("price"));
return entity;
}
},name);
return entities;
}

@Override
public void addEntity(BookEntity entity) {
logger.info("addEntity start");
String sql = "INSERT INTO Book (book_name,price) VALUES (?,?)";
jdbcTemplate.update(sql, entity.getBookName(),entity.getPrice());
}
}

addEntityメソッドの実装。コードは見ての通り、至ってシンプルだ。
SQLと「?」に渡す値を、updateメソッドの引数に渡せばよい。ちなみにサンプルはINSERTだが、UPDATE、DELETEの場合も同様にupdateメソッドを使用する。また、JPAとは異なり、@Transactionalアノテーションを使っていない点も補足しておく。

3.BookService.java


package jp.co.sample.book.service;

import java.util.List;

public interface BookService<T> {

List<T> findAll();
List<T> findByNameLike(String name);
void addEntity(T entity);
}


4.BookServiceImpl.java

package jp.co.sample.book.service;

import java.util.List;

import jp.co.sample.book.dao.BookDao;
import jp.co.sample.book.entity.BookEntity;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class BookServiceImpl implements BookService<BookEntity> {

@Autowired
@Qualifier(value="bookDaoImplTemplate")
BookDao<BookEntity> dao;

@Override
public List<BookEntity> findAll() {
return dao.findAll();
}

@Override
public List<BookEntity> findByNameLike(String name) {
return dao.findByNameLike(name);
}

@Override
public void addEntity(BookEntity entity) {
dao.addEntity(entity);
}
}

@Qualifierアノテーションについては過去のJDBCの記事を参考にしてほしい。
実際の登録処理はDAOに委譲している。

5.動作確認
①登録

登録

②登録後の一覧
登録後一覧

登録したデータがテーブルに反映されていることが確認できた。

JdbcTemplateクラスを使うと、データソースのコネクションの取得や解放など定型処理を記述する必要がなくなる点がメリットかと思うが、特に更新処理は簡単に実装できる。


■過去のSpring関連記事
Spring関連記事 Index

スポンサーサイト

Spring MVC Spring Data JPAを使って登録する(その2)

さて、前回@Transactionalアノテーションを使ってトランザクション制御したが、今回は、@Transactionalアノテーションを使わずに実現してみる。

■前回の記事
Spring MVC Spring Data JPAを使って登録する

◎動作検証にあたっての各バージョンは以下の通り
  • SpringFramework 3.2.8.RELEASE
  • Java 1.7
  • Tomcat 7.0

1.BookDaoImpl.java(エラーパターン)

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
//import文 省略

@Repository
//@Transactional
public class BookDaoImpl implements BookDao<BookEntity> {

private static Logger logger = LoggerFactory.getLogger(BookDaoImpl.class);

@PersistenceContext
private EntityManager manager;

//省略

@Override
public void addEntity(BookEntity entity) {
logger.info("addEntity start");
EntityTransaction transaction = manager.getTransaction();
transaction.begin();
manager.persist(entity);
manager.flush();
transaction.commit();
}
}

@Transactionalアノテーションをコメントアウト。まず、EntityManagerを使ってトランザクション制御を試みる。ソースだけ見ると上手くいきそうであるが、結果「HTTPステータス 500 - Request processing failed; nested exception is java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead」と例外が発生する。
「Not allowed to create transaction on shared EntityManager」とインスタンス変数を使ってトランザクション制御するのがよくないのかなと思い、以下に書き換えてみる。

2.BookDaoImpl.java(正常パターン①)


@Override
public void addEntity(BookEntity entity) {
EntityManager manager2 = manager.getEntityManagerFactory().createEntityManager();
EntityTransaction transaction = manager2.getTransaction();
transaction.begin();
manager2.persist(entity);
manager2.flush();
transaction.commit();
}

インスタンス変数のEntityManagerからcreateEntityManagerメソッドで、新たにEntityManagerを取得すると、例外が発生することなく登録できた。しかしながら、違和感のあるコードである。manager.getEntityManagerFactory()はファクトリークラスを取得していることに着目して、さらに以下のように書き換えてみる。

3.BookDaoImpl.java(正常パターン②)


import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
//import文 省略

@Repository
//@Transactional
public class BookDaoImpl implements BookDao<BookEntity> {

private static Logger logger = LoggerFactory.getLogger(BookDaoImpl.class);

@Autowired
private EntityManagerFactory factory;

//省略

@Override
public void addEntity(BookEntity entity) {
logger.info("addEntity start");
EntityManager manager2 = factory.createEntityManager();
EntityTransaction transaction = manager2.getTransaction();
transaction.begin();
manager2.persist(entity);
manager2.flush();
transaction.commit();

Bean定義ファイル(下記参照)で「entityManagerFactory」を定義しているため、インジェクションできると思い試してみたところ、こちらの方法でも登録できた。明示的にトランザクション制御を行う場合の実装方法は他にもあると思うが、ファクトリークラスからEntityManagerを生成する流れは変わらないはずである。
処理の流れについては見てもらえば分かると思うが、flush()はキャッシュに残っている処理をすべて実行するメソッドとなる点を補足しておく。

4.Bean定義ファイル(datasource-config.xmlより抜粋)


<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"/>
<property name="packagesToScan" value="jp.co.sample.book.entity"/>
</bean>


今回、明示的トランザクションで実装してみたが、前回のアノテーションを使った宣言的トランザクションの方がやはりスマートである。@Transactionalは重宝するアノテーションだ。


■過去のSpring関連記事
Spring関連記事 Index

プロフィール

bookmount8

Author:bookmount8
システムエンジニア。サーバーサイドでjavaを扱うことが多い。最近は、ミドルやフロント周りも関心あり。

最新記事
カテゴリ
検索フォーム
最新コメント
月別アーカイブ
これまでの訪問者数
ブロとも申請フォーム

この人とブロともになる

RSSリンクの表示
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。