Java簡易ORMフレームワークに基づく実装(一)


ORMのフルネームはObject Relational Mapping、すなわちオブジェクト関係マッピングです.その実現思想は,リレーショナル・データベースにおけるテーブルのデータをオブジェクトにマッピングし,オブジェクトの形で示すことであり,開発者はデータベースに対する操作をこれらのオブジェクトに対する操作に変換することができる.そのため,開発者がオブジェクト向けの考え方でデータベースの操作を容易にすることを目的としている.
    仕事のニーズに基づいて、ormフレームワークを自分で書き換える必要がある場合があります.ormコア技術はjava反射メカニズム、汎用などです.
    
package orm;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import util.JdbcUtils;

/**
 * 
 * @author fengzb
 * 
 * @param <T>
 */
public class Orm<T> {

	/**
	 *                    bean
	 * 
	 * @param sql
	 * @param clazz
	 * @return
	 * @throws Exception
	 */
	public T getBean(String sql, Class<T> clazz) throws Exception {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			conn = JdbcUtils.getConnection();
			ps = conn.prepareStatement(sql);
			rs = ps.executeQuery();
			String[] colNames = getColNames(rs);

			T t = null;
			if (rs.next()) {
				t = clazz.newInstance();
				callSetter(t, colNames, rs);
			}
			return t;
		} finally {
			JdbcUtils.free(rs, ps, conn);
		}
	}
	
	/**
	 *                  bean List
	 * 
	 * @param sql
	 * @param clazz
	 * @return
	 * @throws Exception
	 */
	public List<T> getBeanList(String sql, Class<T> clazz) throws Exception {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			conn = JdbcUtils.getConnection();
			ps = conn.prepareStatement(sql);
			rs = ps.executeQuery();
			String[] colNames = getColNames(rs);

			List<T> objects = new ArrayList<T>();
			while (rs.next()) {
				T t = (T) clazz.newInstance(); //
				callSetter(t, colNames, rs);
				objects.add(t);
			}
			return objects;
		} finally {
			JdbcUtils.free(rs, ps, conn);
		}
	}


	/**
	 *              
	 * @param rs
	 * @return
	 * @throws Exception
	 */
	private String[] getColNames(ResultSet rs) throws Exception {
		ResultSetMetaData rsmd = rs.getMetaData();
		int count = rsmd.getColumnCount();
		String[] colNames = new String[count];
		for (int i = 1; i <= count; i++) {
			colNames[i - 1] = rsmd.getColumnLabel(i);
		}
		return colNames;
	}
	
	/**
	 *            ‘set’,  java bean  set  ,          
	 * @param object
	 * @param colNames
	 * @param rs
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws SQLException
	 */
	private void callSetter(T object, String[] colNames, ResultSet rs)
			throws IllegalAccessException, InvocationTargetException,
			SQLException {
		Method[] ms = object.getClass().getMethods();
		for (int i = 0; i < colNames.length; i++) {
			String colName = colNames[i];
			String methodName = "set" + colName;
			for (Method m : ms) {
				if (methodName.equalsIgnoreCase(m.getName())) {
					m.invoke(object, rs.getObject(colName));
					break;
				}
			}
		}
	}
}

 データベーステーブルとjava beanのマッピングは、データベース列名を介してbeanにマッピングされる属性名です.
 
データベーステーブルtb_users
CREATE
    TABLE tb_user
    (
        userId INT NOT NULL AUTO_INCREMENT,
        department VARCHAR(255),
        division VARCHAR(255),
        email VARCHAR(255),
        employeeNo VARCHAR(255),
        name VARCHAR(255),
        passwordMD5 VARCHAR(255),
        phone VARCHAR(255),
        position VARCHAR(255),
        state INT NOT NULL,
        type INT NOT NULL,
        PRIMARY KEY (userId)
    )
    ENGINE=InnoDB DEFAULT CHARSET=utf8

 
JAvaエンティティbeanクラス
package model;

public class User {
	private String	department;
	private String	division;
	private String	email;
	private String	employeeNo;
	private String	name;
	private String	passwordMD5;
	private String	phone;
	private String	position;
	private int	state;
	private int	type;
	private int	userId;
	
	//get set   
	
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "User [userId=" + userId + ", department=" + department
				+ ", division=" + division + ", email=" + email
				+ ", employeeNo=" + employeeNo + ", name=" + name
				+ ", passwordMD5=" + passwordMD5 + ", phone=" + phone
				+ ", position=" + position + ", state=" + state + ", type="
				+ type + "]";
	}
}

 
 
テストクラス
package orm;

import java.util.List;
import model.User;
import org.junit.Test;

public class OrmTest {
	@Test
	public void ormTest() throws Exception{
		Orm<User> orm = new Orm<User>();
		User user= (User) orm.getBean("SELECT userId,department,division,email,employeeNo,name,passwordMD5,phone,position,state,type FROM tb_user",User.class);
		System.out.println(user);

		List<User> userList= orm.getBeanList("SELECT userId,department,division,email,employeeNo,name,passwordMD5,phone,position,state,type FROM tb_user",User.class);
		for(User u : userList){
			System.out.println(u);
		}
	}
}

  データベースのカラム名とbean属性名だけでマッピングするのは簡単で、データベースのカラム名とbean属性名が一致しない場合、
エイリアスによる解決
たとえばbeanではdepart、データベースではdepartment
		User user= (User) orm.getBean("SELECT userId ,department depart,division,email,employeeNo,name,passwordMD5,phone,position,state,type FROM tb_user",User.class);