me-battis
地址:https://gitee.com/null_631_9084/mybatis-cumstor
me-persistent 自定义持久化
me-batis-demo 测试类
接口与配置文件
package com.liu.me.mapper;
import com.liu.me.entity.User;
import javax.jws.soap.SOAPBinding;
import java.util.List;
/**
* @Description
* @ClassName UserMapper
* @Author 刘楠
* @date 2020.06.19
*/
public interface UserMapper {
/**
* 查询所有用户
* @return
*/
List<User> selectList();
/**
* 查询一个用户
* @param user
* @return
*/
User selectOne(User user);
/**
* 获取所有用户
* @return
*/
List<User> findAll();
/**
* 更新用户
* @param user
* @return
*/
Integer update(User user);
/**
* 保存用户
* @param user
* @return
*/
Integer insert(User user);
/**
* 删除用户
* @param user
* @return
*/
Integer delete(User user);
}
sqlMapConfig.xml 数据库名称 mylearning 使用请更换名称
<?xml version="1.0" encoding="UTF-8" ?>
<properties>
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<!--数据库连接地址数据库名称mylearning -->
<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/mylearning"/>
<property name="jdbcUser" value="root"/>
<property name="jdbcPassword" value="root"/>
</properties>
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
``` ``` userMapper.xml ```xml
select * from user where id = #{id} and username =#{username}
select * from user
select * from user
UPDATE user set username=#{username},password=#{password},birthday=#{birthday} where id=#{id}
INSERT INTO user VALUES (#{id},#{username},#{password},#{birthday});
DELETE FROM user where id=#{id} ```
sql
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) DEFAULT NULL,
`password` varchar(50) DEFAULT NULL,
`birthday` date DEFAULT NULL COMMENT '生日',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `user` (`id`, `username`, `password`, `birthday`) VALUES ('1', '333', '123789', '2020-06-22');
INSERT INTO `user` (`id`, `username`, `password`, `birthday`) VALUES ('2', 'tom123', '456', '2019-11-11');
INSERT INTO `user` (`id`, `username`, `password`, `birthday`) VALUES ('3', 'liu123', '789', '2020-01-01');
在第一版的基础上增加更新,删除,修改
增加 SqlCommandType 表示每个mapper中的标签类型
- INSERT 保存
- UPDATE 更新
- DELETE 删除
- SELECT查询
public enum SqlCommandType {
INSERT, UPDATE, DELETE, SELECT;
}
MappedStatement 增加 SqlCommandType 字段
public class MappedStatement {
/**
* ID namespace +"."+id
*/
private String id;
/**
* SQL语句
*/
private String sql;
/**
* 参数类型
*/
private String parameterType;
/**
* 返回值类型
*/
private String returnType;
/**
* 表示这具标签的类型
*/
private SqlCommandType sqlCommandType;
XmlMappedBuilder 中parse方法修改
package com.liu.me.parse;
import com.liu.me.mapping.MappedStatement;
import com.liu.me.session.Configuration;
import com.liu.me.session.SqlCommandType;
import com.mysql.jdbc.exceptions.MySQLQueryInterruptedException;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.InputStream;
import java.util.List;
/**
* @Description
* @ClassName XmlMappedBuilder
* @Author 刘楠
* @date 2020.06.19
*/
public class XmlMappedBuilder {
private Configuration configuration;
public XmlMappedBuilder(Configuration configuration) {
this.configuration = configuration;
}
public void parse(InputStream inputStream) throws DocumentException {
//使用Dom4j
Document document = new SAXReader().read(inputStream);
//获取根对象
Element rootElement = document.getRootElement();
//获取命名空间
String namespace = rootElement.attributeValue("namespace");
//获取xml中的节点
List<Element> selectList=rootElement.selectNodes("//select");
//参数一个参数SELECT,方法在下面
doConfig(namespace,selectList,SqlCommandType.SELECT);
List<Element> updateList= rootElement.selectNodes("//update");
//参数一个参数UPDATE,方法在下面
doConfig(namespace,updateList,SqlCommandType.UPDATE);
List<Element> deleteList= rootElement.selectNodes("//delete");
//参数一个参数DELETE,方法在下面
doConfig(namespace,deleteList,SqlCommandType.DELETE);
List<Element> insertList= rootElement.selectNodes("//insert");
//参数一个参数INSERT,方法在下面
doConfig(namespace,insertList,SqlCommandType.INSERT);
}
/**
对标签解析 封装到MappedStatement 中
list 解析到的标签
SqlCommandType SQL类型
*/
private void doConfig(String namespace,List<Element> list, SqlCommandType sqlCommandType) {
for (Element element : list) {
//id
String id = element.attributeValue("id");
//参数
String paramterType = element.attributeValue("paramterType");
//返回值
String resultType = element.attributeValue("resultType");
//sql
String sqlText = element.getTextTrim();
//封装数据
MappedStatement mappedStatement = new MappedStatement();
//设置标签中的SQL类型
mappedStatement.setSqlCommandType(sqlCommandType);
//id值命名空间.id
String key =namespace+"."+id;
mappedStatement.setId(key);
mappedStatement.setSql(sqlText);
mappedStatement.setReturnType(resultType);
mappedStatement.setParameterType(paramterType);
//放入容器
configuration.getMappedStatementMap().put(key, mappedStatement);
}
}
}
sqlSession增加对象的更新,保存,删除操作
package com.liu.me.session;
import com.liu.me.mapping.MappedStatement;
import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.List;
/**
* @Description
* @ClassName SqlSession
* @Author 刘楠
* @date 2020.06.19
*/
public interface SqlSession {
/**
* @param statementId
* @param params
* @param <E>
* @return
*/
<E> List<E> selectList(String statementId, Object... params) throws SQLException, InvocationTargetException, IntrospectionException, InstantiationException, IllegalAccessException, NoSuchFieldException;
/**
* @param statementId
* @param params
* @return
*/
<T> T selectOne(String statementId, Object... params) throws SQLException, IntrospectionException, InstantiationException, IllegalAccessException, NoSuchFieldException, InvocationTargetException;
/**
* 获取代理Mapper
*
* @param mapperClass
* @param <T>
* @return
*/
<T> T getMapper(Class<T> mapperClass);
/**
* 更新用户
*
* @param statementId
* @param params
* @return
*/
Integer update(String statementId, Object... params) throws NoSuchFieldException, IllegalAccessException, SQLException;
/**
* 保存用户
*
* @param statementId
* @param params
* @return
*/
Integer insert(String statementId, Object... params) throws IllegalAccessException, NoSuchFieldException, SQLException;
/**
* 删除用户
*
* @param statementId
* @param params
* @return
*/
Integer delete(String statementId, Object... params) throws NoSuchFieldException, IllegalAccessException, SQLException;
}
defaultSqlSession中的实现,及修改getMapper方法
package com.liu.me.session;
import com.liu.me.executor.Executor;
import com.liu.me.executor.SimpleExecutor;
import com.liu.me.mapping.MappedStatement;
import java.beans.IntrospectionException;
import java.lang.reflect.*;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* @Description 会话
* @ClassName DefaultSqlSession 默认实现
* @Author 刘楠
* @date 2020.06.19
*/
public class DefaultSqlSession implements SqlSession {
/**
* 醘
*/
private final Configuration configuration;
/**
* 执行器
*/
private Executor executor;
public DefaultSqlSession(Configuration configuration) {
this.configuration = configuration;
executor = new SimpleExecutor();
}
@Override
public <E> List<E> selectList(String statementId, Object... params) throws SQLException, InvocationTargetException, IntrospectionException, InstantiationException, IllegalAccessException, NoSuchFieldException {
executor = new SimpleExecutor();
MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
return executor.query(configuration, mappedStatement, params);
}
@Override
public <T> T selectOne(String statementId, Object... params) throws SQLException, IntrospectionException, InstantiationException, IllegalAccessException, NoSuchFieldException, InvocationTargetException {
List<T> list = selectList(statementId, params);
if (list.size() == 1) {
return list.get(0);
}
throw new RuntimeException("返回结果过多");
}
@Override
public <T> T getMapper(Class<T> mapperClass) {
//使用代理对象
T o = (T) Proxy.newProxyInstance(mapperClass.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法名
String methodName = method.getName();
//类名称 namespace
String className = method.getDeclaringClass().getName();
//ID namespace +"."+id
String key = className + "." + methodName;
//从配置中获取Mapper对象
MappedStatement mappedStatement = configuration.getMappedStatementMap().get(key);
if (mappedStatement.getSqlCommandType() == SqlCommandType.SELECT) {
//判断是查询
//获取返回值
Type returnType = method.getGenericReturnType();
ArrayList arrayList = new ArrayList();
//判断参数是否实现泛型
if (returnType instanceof ParameterizedType) {
return selectList(key, args);
}
return selectOne(key, args);
} else if (mappedStatement.getSqlCommandType() == SqlCommandType.UPDATE) {
//判断是更新
return update(key, args);
} else if (mappedStatement.getSqlCommandType() == SqlCommandType.INSERT) {
//判断是保存
return insert(key, args);
} else if (mappedStatement.getSqlCommandType() == SqlCommandType.DELETE) {
//判断是删除
return delete(key, args);
} else {
return null;
}
}
});
return o;
}
@Override
public Integer update(String statementId, Object... params) throws NoSuchFieldException, IllegalAccessException, SQLException {
executor = new SimpleExecutor();
MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
return executor.update(configuration, mappedStatement, params);
}
@Override
public Integer insert(String statementId, Object... params) throws IllegalAccessException, NoSuchFieldException, SQLException {
executor = new SimpleExecutor();
MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
return executor.insert(configuration, mappedStatement, params);
}
@Override
public Integer delete(String statementId, Object... params) throws NoSuchFieldException, IllegalAccessException, SQLException {
executor = new SimpleExecutor();
MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
return executor.delete(configuration, mappedStatement, params);
}
}
Executor 接口
package com.liu.me.executor;
import com.liu.me.mapping.MappedStatement;
import com.liu.me.session.Configuration;
import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.List;
/**
* @Description
* @ClassName Executor
* @Author 刘楠
* @date 2020.06.19
*/
public interface Executor {
public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement,Object[] params) throws SQLException, NoSuchFieldException, IllegalAccessException, IntrospectionException, InvocationTargetException, InstantiationException;
void close() throws SQLException;
/**
* 更新
* @param configuration
* @param mappedStatement
* @param params
* @return
*/
Integer update(Configuration configuration, MappedStatement mappedStatement, Object[] params) throws SQLException, NoSuchFieldException, IllegalAccessException;
/**
* 保存
* @param configuration
* @param mappedStatement
* @param params
* @return
*/
Integer insert(Configuration configuration, MappedStatement mappedStatement, Object[] params) throws IllegalAccessException, NoSuchFieldException, SQLException;
/**
* 删除
* @param configuration
* @param mappedStatement
* @param params
* @return
*/
Integer delete(Configuration configuration, MappedStatement mappedStatement, Object[] params) throws SQLException, NoSuchFieldException, IllegalAccessException;
}
接口实现 SimpleExecutor
package com.liu.me.executor;
import com.liu.me.mapping.BoundSql;
import com.liu.me.mapping.MappedStatement;
import com.liu.me.session.Configuration;
import com.liu.me.util.GenericTokenParser;
import com.liu.me.util.ParameterMapping;
import com.liu.me.util.ParameterMappingTokenHandler;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* @Description
* @ClassName SimpleExecutor
* @Author 刘楠
* @date 2020.06.19
*/
public class SimpleExecutor implements Executor {
private Connection connection;
@Override
public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object[] params) throws SQLException, NoSuchFieldException, IllegalAccessException, IntrospectionException, InvocationTargetException, InstantiationException {
//1.创建连接
connection = configuration.getDataSource().getConnection();
//2. 获取sql语句 : select * from user where id = #{id} and username = #{username}
// //转换sql语句: select * from user where id = ? and username = ? ,转换的过程中,还需要对#{}里面的值进行解析存储
String sql = mappedStatement.getSql();
BoundSql boundSql = getBoundSql(sql);
//3. 获取预处理对象:preparedStatement
PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
//4. 设置参数
String parameterType = mappedStatement.getParameterType();
Class<?> paramtertypeClass = null;
if (null != parameterType) {
paramtertypeClass = getClassType(parameterType);
}
if (paramtertypeClass != null) {
/* List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
for (int i = 0; i < parameterMappings.size(); i++) {
//获取元素
ParameterMapping mapping = parameterMappings.get(i);
//属性名
String content = mapping.getContent();
//反射获取属性
Field field = paramtertypeClass.getDeclaredField(content);
//设置可访问
field.setAccessible(true);
Object o = field.get(params[0]);
//为SQL中的?设置值
preparedStatement.setObject(i + 1, o);
}*/
//解析参数
doParseParams(mappedStatement, params[0], boundSql, preparedStatement);
}
//5. 执行sql
ResultSet resultSet = preparedStatement.executeQuery();
//6.结果封装
String returnType = mappedStatement.getReturnType();
Class<?> resultTypeClass = getClassType(returnType);
List<Object> objects = new ArrayList<>();
while (resultSet.next()) {
Object newInstance = resultTypeClass.newInstance();
//元数据
ResultSetMetaData metaData = resultSet.getMetaData();
//获取列组
int columnCount = metaData.getColumnCount();
//从1开始
for (int i = 1; i <=columnCount; i++) {
//获取名
String columnName = metaData.getColumnName(i);
//获取查询出的出来值
Object value = resultSet.getObject(columnName);
//使用反射java.beans中的内省
PropertyDescriptor descriptor = new PropertyDescriptor(columnName, resultTypeClass);
//获取写方法
Method writeMethod = descriptor.getWriteMethod();
writeMethod.invoke(newInstance, value);
}
objects.add(newInstance);
}
return (List<E>)objects;
}
@Override
public void close() throws SQLException {
if (connection != null) {
connection.close();
}
}
@Override
public Integer update(Configuration configuration, MappedStatement mappedStatement, Object[] params) throws SQLException, NoSuchFieldException, IllegalAccessException {
//1.创建数据库连接
connection=configuration.getDataSource().getConnection();
//2.获取sql并处理SQL中的占位符
BoundSql boundSql = getBoundSql(mappedStatement.getSql());
//3.获取预处理对象
PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
//解析参数
doParseParams(mappedStatement, params[0], boundSql, preparedStatement);
//执行sql
int reslut = preparedStatement.executeUpdate();
return reslut;
}
@Override
public Integer insert(Configuration configuration, MappedStatement mappedStatement, Object[] params) throws IllegalAccessException, NoSuchFieldException, SQLException {
//1.创建数据库连接
connection=configuration.getDataSource().getConnection();
//2.获取sql并处理SQL中的占位符
BoundSql boundSql = getBoundSql(mappedStatement.getSql());
//3.获取预处理对象
PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
//解析参数
doParseParams(mappedStatement, params[0], boundSql, preparedStatement);
//执行sql
int reslut = preparedStatement.executeUpdate();
return reslut;
}
@Override
public Integer delete(Configuration configuration, MappedStatement mappedStatement, Object[] params) throws SQLException, NoSuchFieldException, IllegalAccessException {
//1.创建数据库连接
connection=configuration.getDataSource().getConnection();
//2.获取sql并处理SQL中的占位符
BoundSql boundSql = getBoundSql(mappedStatement.getSql());
//3.获取预处理对象
PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
//解析参数
doParseParams(mappedStatement, params[0], boundSql, preparedStatement);
//执行sql
int reslut = preparedStatement.executeUpdate();
return reslut;
}
private Class<?> getClassType(String paramterType) {
if (paramterType != null) {
Class<?> aClass = null;
try {
aClass = Class.forName(paramterType);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return aClass;
}
return null;
}
/**
* 完成对#{}的解析工作:1.将#{}使用?进行代替,2.解析出#{}里面的值进行存储
*
* @param sql
* @return
*/
private BoundSql getBoundSql(String sql) {
//标记处理类:配置标记解析器来完成对占位符的解析处理工作
ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", parameterMappingTokenHandler);
//解析出来的sql
String parseSql = genericTokenParser.parse(sql);
//#{}里面解析出来的参数名称
List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();
BoundSql boundSql = new BoundSql(parseSql, parameterMappings);
return boundSql;
}
private void doParseParams(MappedStatement mappedStatement, Object param, BoundSql boundSql, PreparedStatement preparedStatement) throws NoSuchFieldException, IllegalAccessException, SQLException {
//4.处理参数
String parameterType = mappedStatement.getParameterType();
Class<?> paramsTypeClass = getClassType(parameterType);
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping arameterMapping = parameterMappings.get(i);
//获取占位符中的名称
String propertyName = arameterMapping.getContent();
//反射获取属性
Field field = paramsTypeClass.getDeclaredField(propertyName);
//设置可以访问
field.setAccessible(true);
Object value = field.get(param);
//为SQL中的?设置值
preparedStatement.setObject(i+1, value);
}
}
}
测试