DBアクセスのサンプル

Spring frameworkを使うとDBまわりのコードがすっきりするらしいので、練習兼メモがてらサンプルを書いてみた。


RDBMSは何でも良いのだけどPostgreSQLで。適当なテーブルを用意しておく。

sample=# \c
psql (8.4.4)
You are now connected to database "sample".
sample=# \d users 
          Table "public.users"
 Column |       Type        | Modifiers 
--------+-------------------+-----------
 id     | integer           | 
 name   | character varying | 
 age    | integer           | 


ValueObject(っていうの?)はこんなの。

public class User {
	private final int id;
	private final String name;
	private final int age;
	
	public User(int id, String name, int age) {
		this.id = id;
		this.name = name;
		this.age = age;
	}
	
	public int getId() {
		return id;
	}
	
	public String getName() {
		return name;
	}
	
	public int getAge() {
		return age;
	}
}


で、肝心のDAOはこんな感じ。PreparedStatementが無いし、毎度毎度の例外処理も無くてすっきり。JdbcDaoSupport、MappingSqlQuery、SqlUpdate 辺りのクラスが鍵。

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

import javax.sql.DataSource;

import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.jdbc.object.MappingSqlQuery;
import org.springframework.jdbc.object.SqlUpdate;

public class UserDao extends JdbcDaoSupport {
	private static class FindUser extends MappingSqlQuery {
		private static final String SQL =
			"SELECT id, name, age FROM users";

		private FindUser(DataSource ds) {
			super(ds, SQL);
		}

		@Override
		protected User mapRow(ResultSet rs, int rowNum) throws SQLException {
			return new User(rs.getInt("id"), rs.getString("name"), rs.getInt("age"));
		}
	}
	
	private static class InsertUser extends SqlUpdate {
		private static final String SQL =
			"INSERT INTO users (id, name, age)" +
			"VALUES (NEXTVAL('seq_users_id'), ?, ?)";
		
		private InsertUser(DataSource ds) {
			super(ds, SQL);
			declareParameter(new SqlParameter("name", Types.VARCHAR));
			declareParameter(new SqlParameter("age", Types.INTEGER));
		}
	}
	
	private FindUser fu = null;
	private InsertUser iu = null;
	
	protected void initDao() {
		this.fu = new FindUser(getDataSource());
		this.iu = new InsertUser(getDataSource());
	}
	
	public List<User> findUser() {
		@SuppressWarnings("unchecked") List<User> users = fu.execute();
		return users;
	}
	
	public void insertUser(String name, int age) {
		Object[] params = { name, age };
		iu.update(params);
	}
}


で、これらを利用するコードはこちら。

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

public class Main {
	public static void main(String[] argv) {
		Resource resource = new ClassPathResource("applicationContext.xml");
		BeanFactory bf = new XmlBeanFactory(resource);
		UserDao udao = (UserDao) bf.getBean("userDao");
		udao.insertUser("Foo", 64);
		udao.insertUser("Bar", 72);
		
		for (User user : udao.findUser()) {
			System.out.printf("%3d: %s: %3d\n", user.getId(),
								 user.getName(), user.getAge());
		}
	}
}


あと、DIの設定はこれ。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
		http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName">
			<value>org.postgresql.Driver</value></property>
		<property name="url">
			<value>jdbc:postgresql://localhost/sample</value></property>
		<property name="username">
			<value>komamitsu</value></property>
	</bean>
	<bean id="userDao" class="UserDao">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
</beans>


これを実行すると。

  1: Foo:  64
  2: Bar:  72

となり成功。


ちょっと悔しいのは、UserDao.findUser()で警告を消すために@SuppressWarnings("unchecked")を使っていること。もう一回, Effective Javaジェネリクスの章を読み直して、再挑戦したい。