MyBatisのシンプルなフレームワークのソースコードの実装

MyBatisのシンプルなフレームワークのソースコードの実装

ソースのダウンロード
ここに画像を挿入説明

MyBatisのフレームワークを作成し、我々は最初に、次のことを行う必要があり
、パッケージから抽出した構成情報と、エンティティクラスの設定とMapperStatementに対応する設定情報を作成します。1.
2. SqlSessionFactoryファクトリクラスを作成し、負荷の設定情報
3. SqlSessionFactoryで作成しますSQLSESSION
SQLSESSION動的プロキシ・インターフェース・マッパーが取得4.
における動的コールバックプロキシSQLSESSIONに記載の方法照会
エグゼキュータアクチュエータにクエリを送信する6.SqlSession方法
アクチュエータデータベース接続7.
反射ステートメントによってアクチュエータ8が実行され、戻りgeiSqlSession
9.データは、呼び出し元に返されます

まず、我々は、XMLエンティティクラスのパッケージをロードします

package com.ys.config;
/**
 * 解析xml配置文件中的标签含义
 * @author ys
 */
public class MappedStatement {
	//namespace标签
	private String namespace;
	//SQL语句标签的id属性
	private String sourceId;
	//返回值类型标签
	private String resultType;
	//存储sql语句
	private String sql;
	public String getNamespace() {
		return namespace;
	}
	public void setNamespace(String namespace) {
		this.namespace = namespace;
	}
	public String getSourceId() {
		return sourceId;
	}
	public void setSourceId(String sourceId) {
		this.sourceId = sourceId;
	}
	public String getResultType() {
		return resultType;
	}
	public void setResultType(String resultType) {
		this.resultType = resultType;
	}
	public String getSql() {
		return sql;
	}
	public void setSql(String sql) {
		this.sql = sql;
	}
}

エンティティクラスのファイルパッケージのプロパティを作成します。

このクラスでは、情報は、マップセット内のXML構成ファイルに格納された
キー値としてパッケージ名+メソッド名
オブジェクトクラスの値としてXML値をカプセル化

package com.ys.config;

import java.util.HashMap;
import java.util.Map;

/**
 * 这是一个更大的存储配置信息的文件
 * 
 * 加载properties文件
 * @author ys
 */
public class Configuration {
	//加载properties配置文件中的连接数据库的信息
	private String jdbcDriver;
	private String jdbcUrl;
	private String jdbcUsername;
	private String jdbcPassword;
	//存储多个xml文件
	private Map<String,MappedStatement> mappedStatement = new HashMap<String, MappedStatement>();
	
	public String getJdbcDriver() {
		return jdbcDriver;
	}
	public void setJdbcDriver(String jdbcDriver) {
		this.jdbcDriver = jdbcDriver;
	}
	public String getJdbcUrl() {
		return jdbcUrl;
	}
	public void setJdbcUrl(String jdbcUrl) {
		this.jdbcUrl = jdbcUrl;
	}
	public String getJdbcUsername() {
		return jdbcUsername;
	}
	public void setJdbcUsername(String jdbcUsername) {
		this.jdbcUsername = jdbcUsername;
	}
	public String getJdbcPassword() {
		return jdbcPassword;
	}
	public void setJdbcPassword(String jdbcPassword) {
		this.jdbcPassword = jdbcPassword;
	}
	public Map<String, MappedStatement> getMappedStatement() {
		return mappedStatement;
	}
	public void setMappedStatement(Map<String, MappedStatement> mappedStatement) {
		this.mappedStatement = mappedStatement;
	}
}

sqlsessionfactoryクラス(二つの関数、1ローディング設定情報生成SQLSESSION)

package com.ys.session;
/**
 *1.在初始化是加载配置信息到configuration
 *2.生成sqlSession
 * @author ys
 */

import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.List;
import java.util.Properties;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.ys.config.Configuration;
import com.ys.config.MappedStatement;

public class SqlSessionFactory {
	//全局唯一的对象
	private final Configuration conf = new Configuration();
	
	public SqlSessionFactory(){
		//实例化时加载db.properties的数据库配置信息
		loadDbInfo();
		//将多个xml配置文件加载到Configuration对象中
		loadMappersInfo();
	}
	//记录mapper.xml文件存储位置
	public static final String MAPPER_CONFIG_LOCATION = "mappers";
	//记录连接数据库连接信息文件的存储位置
	public static final String DB_CONFIG_FILE = "db.properties";
	
	//加载数据库配置信息
	private void loadMappersInfo() {
		//加载数据库信息配置文件
		InputStream dbIn = SqlSessionFactory.class.getClassLoader().getResourceAsStream(DB_CONFIG_FILE);
		//持久化存储集合
		Properties p = new Properties();
		try{
			//读取配置文件中的信息.写入Properties对象
			p.load(dbIn);
		}catch (Exception e) {
			e.printStackTrace();
		}
		/*
		 *  jdbc.driver=com.mysql.jdbc.Driver
			jdbc.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
			jdbc.username=root
			jdbc.password=root
		 */
		//将数据库配置信息写入conf对象
		conf.setJdbcDriver(p.get("jdbc.driver").toString());
		conf.setJdbcUrl(p.get("jdbc.url").toString());
		conf.setJdbcUsername(p.get("jdbc.username").toString());
		conf.setJdbcPassword(p.get("jdbc.password").toString());
	}
	
	//加载指定文件夹下的所有.xml文件
	private void loadDbInfo() {
		//创建mapper.xml的存储文件夹
		URL resources = null;
		//赋予路径
		resources = SqlSessionFactory.class.getClassLoader().getResource(MAPPER_CONFIG_LOCATION);
		//获取指定文件夹信息
		File mappers = new File(resources.getFile());
		//遍历文件
		if(mappers.isDirectory()){
			//将该文件夹下所有目录和文件存储
			File[] listFiles = mappers.listFiles();
			//遍历文件夹下所有mapper.xml,解析信息后,注册至conf
			for (File file : listFiles) {
				//判断是否是xml文件
//				if(file.getName().endsWith(".xml")){
					loadMapperInfo(file);
//				}
			}
		}
	}

	//加载指定的
	private void loadMapperInfo(File file) {
		//创建saxReader对象
		SAXReader reader = new SAXReader();
		//通过read方法读取一个文件转换成Document对象
		Document document = null;
		try{
			document = reader.read(file);
		}catch (Exception e) {
			e.printStackTrace();
		}
		//获取节点元素mapper/根节点
		Element root = document.getRootElement();
		//获取命名空间
		String namespace = root.attribute("namespace").getData().toString();
		//获取select子节点列表
		List<Element>  selects = root.elements("select"); 
		//遍历select节点,将信息记录到MappedStatement对象,并记录到Configuration对象中的map中
		for (Element element : selects) {
			//实例化MappedStatement
			MappedStatement mappedStatement = new MappedStatement();
			//选取id属性
			String id = element.attribute("id").getData().toString();
			//获取resultType属性
			String resultType = element.attribute("resultType").getData().toString();
			//读取sql语句信息
			String sql = element.getData().toString();
			//对 namespace和id属性进行拼接
			String sourceId = namespace+"."+id;
			//将信息封装到mappedStatement对象中
			mappedStatement.setSourceId(sourceId);
			mappedStatement.setResultType(resultType);
			mappedStatement.setSql(sql);
			mappedStatement.setNamespace(namespace);
			//注册到Configuration实例化对象map集合中
			conf.getMappedStatement().put(sourceId, mappedStatement);
		}
	}
	
	
	//第二功能  生成sqlsession
	public SqlSession openSession(){
		return new DefaultSqlSession(conf);
	}
}

SQLSESSIONインタフェースクラス

package com.ys.session;

import java.util.List;

/**
 * mybatis暴露给外部的接口,实现增删改查的能力
 * @author ys
 *
 *1.对外提供数据访问的API
 *2.对内将请求转发给executor
 */
public interface SqlSession {
	/**
	 * 根据传入的条件查询单一结果
	 * 
	 * @param statement 方法对应的sql语句 
	 * @param parameter 要传入到SQL语句中的查询参数
	 * @return 返回指定的结果对象
	 */
	<T> T selectOne(String statement,Object parameter);
	
	/**
	 * 根据条件经过查询,返回泛型集合
	 * @param statement 方法对应的sql语句 
	 * @param parameter 要传入到SQL语句中的查询参数
	 * @return 返回指定的结果对象
	 */
	<E> List<E> selectList(String statement,Object parameter);
	/**
	 * 根据mapper接口获取接口对应的动态代理实现
	 * @param type 指定的mapper接口
	 * @return		
	 */
	<T> T getMapper(Class<T> type);
}

SQLSESSION実装クラス

外部に実装される方法(直接パッケージ構成オブジェクトへのマップの優れたコレクションが、対応するSQL文を取得する)を提供する。1.
2.取得アクチュエータ
3動的インターフェイスプロキシオブジェクトを

package com.ys.session;
import java.lang.reflect.Proxy;
/**
 * mybatis暴露给外部的接口,实现增删该查的能力
 * @author ys
 * 
 * 1.对外提供数据访问的API
 * 2.对内将请求转发给executor
 */
import java.util.List;

import com.ys.Executor.DefaultExecutor;
import com.ys.Executor.Executor;
import com.ys.binding.MapperProxy;
import com.ys.config.Configuration;
import com.ys.config.MappedStatement;

public class DefaultSqlSession implements SqlSession{
	//获取容器(加了final字段内存地址不会改变,不可修改,这样就可以提升效率)
	private final Configuration conf;
	//获取执行器
	private Executor executor;
	
	
	public DefaultSqlSession(Configuration conf){
		super();
		this.conf = conf;
		//加载执行器
		executor = new DefaultExecutor(conf);
	}
	
	
	public <T> T selectOne(String statement, Object parameter) {
		List<Object> selectList = this.selectList(statement, parameter);
		if(selectList == null || selectList.size() == 0){
			return null;
		}
		if(selectList.size() == 1){
			//类型强转
			return (T) selectList.get(0);
		}else{
			throw new RuntimeException("Too Many Results!");
		}
	}

	public <E> List<E> selectList(String statement, Object parameter) {
		//获取方法对应的SQL语句
		MappedStatement ms = conf.getMappedStatement().get(statement);
		return executor.query(ms, parameter);
	}
	
	//等待传入接口类型
	public <T> T getMapper(Class<T> type) {
		MapperProxy mp = new MapperProxy(this);
		//生成动态代理对象
		return (T) Proxy.newProxyInstance(
				type.getClassLoader(),
				new Class[]{type}, 
				mp);
	}
}

達成するための動的な代理店事業

1.メソッド名を縫い合わせることにより、オブジェクトの後にメソッド名の名前を取得し、あなたがのキー値のマップを見つけることができ
ますが、パラメータを渡す必要があるかどうかを判断するために2 SQL文を

package com.ys.binding;
/**
 * 动态代理业务逻辑实现
 */
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Collection;

import com.ys.session.SqlSession;

public class MapperProxy implements InvocationHandler {
	
	private SqlSession session;
	
	public MapperProxy(SqlSession session) {
		super();
		this.session = session;
	}

	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		//获取调用方法的返回类型
		Class<?> returnType = method.getReturnType();
		//如果返回值是集合类
		if(Collection.class.isAssignableFrom(returnType)){
			//第一个参数:获取类名全写+方法名(即Configuration对象中的map的key值)
			//第二个参数:简写,应该写成集合返回,这里只写了第一个测试
			return session.selectList(method.getDeclaringClass().getName()+"."+method.getName(), 
									args == null?null:args[0]);
		}else{
			return session.selectOne(method.getDeclaringClass().getName()+"."+method.getName(), 
					args == null?null:args[0]);
		}
	}
}

アクチュエーターインターフェイス

package com.ys.Executor;

import java.util.List;

import com.ys.config.MappedStatement;

/**
 * Mybatis的核心接口之一,定义了数据库的最基本的方法,sqlsession的功能都是基于它实现的
 * @author TEDU
 *
 */
public interface Executor {
	/**
	 * 查询接口
	 * @param ms		封装sql语句的MappedStatement参数
	 * @param parameter 传入sql的参数
	 * @return			将数据转换成指定对象的结果集返回
	 */
	<E> List<E> query(MappedStatement ms ,Object parameter);
}

アクチュエータ実装クラス

まずデータベースへの接続を取得
2. perpreparedStatementプレースホルダの工程
3.クエリタイプの戻り値にデータパッケージを

package com.ys.Executor;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import com.ys.config.Configuration;
import com.ys.config.MappedStatement;
import com.ys.util.ReflectionUtil;

public class DefaultExecutor implements Executor{
	
	private final Configuration conf;
	
	public DefaultExecutor(Configuration conf) {
		super();
		this.conf = conf;
	}
	
	/**
	 * @param ms 封装sql语句MappsedStatement对象
	 * @param parameter 传入的sql参数
	 * @return 将数据转换成指定的对象结果集返回
	 */
	//实现JDBC规范,对数据库进行连接
	public <E> List<E> query(MappedStatement ms, Object parameter) {
//		System.out.println(ms.getSql());
//		System.out.println(ms.getResultType());
		//定义返回结果集
		List<E> ret = new ArrayList<E>();
		try{
			//加载数据驱动
			Class.forName(conf.getJdbcDriver());
		}catch (Exception e) {
			e.printStackTrace();
		}
		//获取连接
		Connection connection = null;
		//执行数据库语句
		PreparedStatement preparedStatement = null;
		//返回结果集
		ResultSet resultSet = null;
		try{
			//获取连接,从MappedStatement对象中获取数据库信息
			connection = DriverManager.getConnection(conf.getJdbcUrl(),conf.getJdbcUsername(),conf.getJdbcPassword());
			//创建preparedStatement,从MappedStatement中获取sql语句
			preparedStatement = connection.prepareStatement(ms.getSql());
			//处理sql语句中的占位符
			parameterized(preparedStatement,parameter);
			//执行查询结果获取resultSet
			resultSet = preparedStatement.executeQuery();
			//将结果集通过反射技术,填充到list集合中
			handlerResultSet(resultSet,ret,ms.getResultType());
		}catch (Exception e) {
			e.printStackTrace();
		}finally{
			try{
				resultSet.close();
				preparedStatement.close();
				connection.close();
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
		return ret;
	}


	//读取result中的数据,并转换成目标对象
	private <E> void handlerResultSet(ResultSet resultSet, List<E> ret, String className) {
		Class<E> clazz = null;
		try{
			//通过反射获取类对象
			clazz = (Class<E>) Class.forName(className);
		}catch (Exception e) {
			e.printStackTrace();
		}
		try{
			while(resultSet.next()){
				//通过反射实例化对象
				Object entity = clazz.newInstance();
				//使用反射工具类将resultSet中的数据填充到entity中
				ReflectionUtil.setPropToBeanFromResultSet(entity, resultSet);
				//对象加入返回集合中
				ret.add((E) entity);
			}
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	//对perpreparedStatement占位符进行处理
	private void parameterized(PreparedStatement preparedStatement, Object parameter) throws SQLException {
		if(parameter instanceof Integer){
			preparedStatement.setInt(1, (Integer) parameter);
		}else if(parameter instanceof Long){
			preparedStatement.setLong(1,  (Long) parameter);
		}else if(parameter instanceof String){
			preparedStatement.setString(1, (String) parameter);
		}
	}
}

ツールリフレクション

オブジェクトの戻り値の実装を支援するためにデータを追加します。

package com.ys.util;
import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.ys.entity.TUser;

/**
 * 反射工具类
 * @author ys
 *
 */
public class ReflectionUtil {
	/**
	 * 为指定的beanpropName属性的值设置为value
	 * 
	 * @param bean   目标对象
	 * @param proName对象的属性名
	 * @param value	 值
	 */
	public static void setPropToBean(Object bean ,String proName,Object value){
		Field f;
		try{
			//获取对象指定的属性
			f = bean.getClass().getDeclaredField(proName);
			//将字段设置为可通过反射访问
			f.setAccessible(true);
			//为属性赋值
			f.set(bean, value);
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	/**
	 * 从resultSet中读取一行数据,并填充到指定的实体bean
	 * @param entity    	待填充的实体bean
	 * @param resultSet		从数据库中加载的数据
	 * @throws SQLException 
	 */
	public static void setPropToBeanFromResultSet(Object entity,ResultSet resultSet) throws SQLException{
		//通过反射获取对象的所有字段
		Field[] declaredFields = entity.getClass().getDeclaredFields();
		//遍历所有的字段,从resultSet中读取相应的电话机,并填充至对象的属性中
		for (int i = 0; i < declaredFields.length; i++) {
			//如果是字符串类型的数据
			if(declaredFields[i].getType().getSimpleName().equals("String")){
				setPropToBean(entity, declaredFields[i].getName(), resultSet.getString(declaredFields[i].getName()));
			//如果是int类型
			}else if(declaredFields[i].getType().getSimpleName().equals("Integer")){
				setPropToBean(entity, declaredFields[i].getName(), resultSet.getInt(declaredFields[i].getName()));
			//如果是long类型数据
			}else if(declaredFields[i].getType().getSimpleName().equals("Long")){
				setPropToBean(entity, declaredFields[i].getName(), resultSet.getLong(declaredFields[i].getName()));
			}
		}
	}
	
	
	//测试
	public static void main(String[] args) {
		TUser user = new TUser();
		ReflectionUtil.setPropToBean(user, "userName", "ys");
		System.out.println(user.getUserName());
	}
}

データコールバックgeisqlsession、あなたはSQLSESSIONにクエリオブジェクトの結果から抜け出すことができます

データベースエンティティクラス

package com.ys.entity;

public class TUser {
	private Integer id;
	private String userName;
	private String realName;
	private String sex;
	private String mobile;
	private String email;
	private String note;
	private Integer position_id;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getRealName() {
		return realName;
	}
	public void setRealName(String realName) {
		this.realName = realName;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public String getmobile() {
		return mobile;
	}
	public void setmobile(String mobile) {
		this.mobile = mobile;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public String getNote() {
		return note;
	}
	public void setNote(String note) {
		this.note = note;
	}
	public Integer getPosition_id() {
		return position_id;
	}
	public void setPosition_id(Integer position_id) {
		this.position_id = position_id;
	}
	@Override
	public String toString() {
		return "TUser [id=" + id + ", userName=" + userName + ", realName=" + realName + ", sex=" + sex + ", mobile="
				+ mobile + ", email=" + email + ", note=" + note + ", position_id=" + position_id + "]";
	}
}

プロパティプロファイル

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
jdbc.username=root
jdbc.password=root

XML設定ファイル

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ys.mapper.TUserMapper">
	<select id="selectByPrimaryKey" resultType="com.ys.entity.TUser">
		select 
			id ,userName, realName, sex, mobile, email,note,position_id
		from t_user where id = ?
	</select>
	<select id="selectAll" resultType="com.ys.entity.TUser">
		select 
			id ,userName, realName, sex, mobile, email,note,position_id
		from t_user
	</select>

</mapper>

マッパーインタフェース

package com.ys.mapper;

import java.util.List;

import com.ys.entity.TUser;

public interface TUserMapper {
	
	TUser selectByPrimaryKey(Integer id);
	List<TUser> selectAll();
}

データベースの構造

ここに画像を挿入説明

テストカテゴリ

package com.ys;

import java.util.List;

import com.ys.entity.TUser;
import com.ys.mapper.TUserMapper;
import com.ys.session.SqlSession;
import com.ys.session.SqlSessionFactory;

public class TestMybatis {
	public static void main(String[] args) {
		//1.实例化sqlsessionfactory,加载数据配置文件及mapper.xml文件到configuration对象中
		SqlSessionFactory factory = new SqlSessionFactory();
		//2.获取sqlsession对象
		SqlSession session = factory.openSession();
		//3.通过动态代理跨域面向接口编程和ibatis编程模型的鸿沟
		TUserMapper userMapper = session.getMapper(TUserMapper.class);
		//4.遵循jdbc规范,通过底层的四大对象的合作完成数据查询和数据转化
		TUser user = userMapper.selectByPrimaryKey(2);
		System.out.println(user);
		
		System.out.println(
				"-----------------------------------------------"
				+ "---------------------------------------------"
				+ "------------------");
		List<TUser> selectAll = userMapper.selectAll();
		if(selectAll != null && selectAll.size() > 0){
			for (TUser tuser : selectAll) {
				System.out.println(tuser);
			}
		}
	}
}

結果

ここに画像を挿入説明

おすすめ

転載: blog.csdn.net/yang134679/article/details/89073309