MyBatis(四):自定义持久层框架优化
2024-08-28 10:15:16
本文所有代码已上传至码云:https://gitee.com/rangers-sun/mybatis
修改IUserDao、UserMapper.xml
package com.rangers; import com.rangers.entity.User; import java.util.List; /**
* @Author Rangers
* @Description 用户数据库访问Dao
* @Date 2021-03-07
**/
public interface IUserDao { /**
* @Author Rangers
* @Description 查询所有用户信息
* @Date 2021/3/7 10:43 上午
* @Return: java.util.List<com.rangers.entity.User>
**/
public List<User> selectList(); /**
* @Author Rangers
* @Description 根据条件查询单个用户信息
* @Date 2021/3/7 10:43 上午
* @Param user:
* @Return: com.rangers.entity.User
**/
public User selectOne(User user) ; Integer insert(User user); Integer update(User user); Integer delete(User user);
}
<mapper namespace="com.rangers.IUserDao"> <select id="selectOne" parameterType="com.rangers.entity.User" resultType="com.rangers.entity.User">
select * from user where id=#{id} and name=#{name}
</select> <select id="selectList" parameterType="com.rangers.entity.User" resultType="com.rangers.entity.User">
select * from user
</select> <insert id="insert" parameterType="com.rangers.entity.User" resultType="java.lang.Integer">
insert into user(id,name,address) values(#{id},#{name},#{address})
</insert> <update id="update" parameterType="com.rangers.entity.User" resultType="java.lang.Integer">
update user set name=#{name},address=#{address} where id=#{id}
</update> <delete id="delete" parameterType="com.rangers.entity.User" resultType="java.lang.Integer">
delete from user where id=#{id}
</delete>
</mapper>
新增SqlCommondType 修改MappedStatement、XmlMapperBuilder
package com.rangers.persistent.config; /**
* @Author Rangers
* @Description
* @Date 2021-03-08
**/
public enum SqlCommondType { INSERT, DELETE, UPDATE, SELECT;
}
package com.rangers.persistent.config.pojo; import com.rangers.persistent.config.SqlCommondType; /**
* @Author Rangers
* @Description 对应Mapper中标签的信息
* @Date 2021-03-04
**/
public class MappedStatement {
// id当前xml中的唯一标识
private String id; // sql语句
private String sql; // 参数类型
private String paramterType; // 返回结果类型
private String resultType; // 返回结果类型
private SqlCommondType sqlCommondType; public String getId() {
return id;
} public void setId(String id) {
this.id = id;
} public String getSql() {
return sql;
} public void setSql(String sql) {
this.sql = sql;
} public String getParamterType() {
return paramterType;
} public void setParamterType(String paramterType) {
this.paramterType = paramterType;
} public String getResultType() {
return resultType;
} public void setResultType(String resultType) {
this.resultType = resultType;
} public SqlCommondType getSqlCommondType() {
return sqlCommondType;
} public void setSqlCommondType(SqlCommondType sqlCommondType) {
this.sqlCommondType = sqlCommondType;
}
}
package com.rangers.persistent.config; import com.rangers.persistent.config.pojo.Configuration;
import com.rangers.persistent.config.pojo.MappedStatement;
import org.apache.commons.collections.CollectionUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader; import java.io.InputStream;
import java.util.ArrayList;
import java.util.List; /**
* @Author Rangers
* @Description 解析XxMapper.xml
* @Date 2021-03-04
**/
public class XmlMapperBuilder {
private Configuration configuration; public XmlMapperBuilder(Configuration configuration) {
this.configuration = configuration;
} public void parse(InputStream inputStream) {
Document document = null;
try {
document = new SAXReader().read(inputStream);
} catch (DocumentException e) {
e.printStackTrace();
}
Element rootElement = document.getRootElement(); String namespace = rootElement.attributeValue("namespace"); List<Element> elements = new ArrayList<>();
List<Element> selectElements = rootElement.selectNodes("//select");
elements.addAll(selectElements);
List<Element> insertElements = rootElement.selectNodes("//insert");
elements.addAll(insertElements);
List<Element> updateElements = rootElement.selectNodes("//update");
elements.addAll(updateElements);
List<Element> deleteElements = rootElement.selectNodes("//delete");
elements.addAll(deleteElements);
// 解析XxMapper.xml中的标签
this.parseLabel(namespace, elements);
} private void parseLabel(String namespace, List<Element> selectElements) {
if (CollectionUtils.isNotEmpty(selectElements)){
selectElements.forEach(mapperElement->{
String id = mapperElement.attributeValue("id");
String sql = mapperElement.getTextTrim();
String parameterType = mapperElement.attributeValue("parameterType");
String resultType = mapperElement.attributeValue("resultType");
String sqlCommondType = mapperElement.getName(); MappedStatement mappedStatement = new MappedStatement();
mappedStatement.setId(id);
mappedStatement.setSql(sql);
mappedStatement.setParamterType(parameterType);
mappedStatement.setResultType(resultType);
mappedStatement.setSqlCommondType(SqlCommondType.valueOf(sqlCommondType.toUpperCase()));
configuration.getMappedStatementMap().put(namespace +"."+id,mappedStatement);
});
}
} }
修改SqlSession、DefaultSqlSession
package com.rangers.persistent.sqlSession; import java.sql.SQLException;
import java.util.List; /**
* @Author Rangers
* @Description
* @Date 2021-03-04
**/
public interface SqlSession { <E> List<E> selectList(String statementId,Object...param) throws Exception; <T> T selectOne(String statementId,Object...param) throws Exception; Integer insert(String statementId,Object...param) throws Exception; Integer update(String statementId,Object...param) throws Exception; Integer delete(String statementId,Object...param) throws Exception; void close() throws SQLException; <T> T getMapper(Class<T> t);
}
package com.rangers.persistent.sqlSession; import com.rangers.persistent.config.SqlCommondType;
import com.rangers.persistent.config.pojo.Configuration;
import com.rangers.persistent.config.pojo.MappedStatement;
import com.rangers.persistent.executor.Executor;
import com.rangers.persistent.executor.SimpleExecutor;
import org.apache.commons.collections.CollectionUtils; import java.lang.reflect.*;
import java.sql.SQLException;
import java.util.List; /**
* @Author Rangers
* @Description
* @Date 2021-03-04
**/
public class DefaultSqlSession implements SqlSession{ private Configuration configuration; public DefaultSqlSession(Configuration configuration) {
this.configuration = configuration;
} private Executor executor = new SimpleExecutor(); @Override
public <E> List<E> selectList(String statementId, Object... params) throws Exception {
MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
return executor.query(configuration,mappedStatement,params);
} @Override
public <T> T selectOne(String statementId, Object... params) throws Exception {
List<Object> objects = this.selectList(statementId, params);
if (CollectionUtils.isNotEmpty(objects)){
if (objects.size() == 1){
return (T) objects.get(0);
}else {
throw new Exception("返回多条记录");
}
}
return null;
} @Override
public Integer insert(String statementId, Object... param) throws Exception {
MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
return executor.insert(configuration,mappedStatement,param);
} @Override
public Integer update(String statementId, Object... param) throws Exception {
MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
return executor.update(configuration,mappedStatement,param);
} @Override
public Integer delete(String statementId, Object... param) throws Exception {
MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
return executor.delete(configuration,mappedStatement,param);
} @Override
public void close() throws SQLException {
executor.close();
} /**
* @Author Rangers
* @Description 使用JDK动态代理获取执行的Mapper对象
**/
@Override
public <T> T getMapper(Class<T> t) {
Object o = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{t}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 全限定性类名==XxMapper.xml的namespace
String className = method.getDeclaringClass().getName();
// 接口的方法名称==XxMapper.xml的每个mapper标签的id
String methodName = method.getName(); // 1、构造statementID:namespace+"."+id
String statementId = className+"."+methodName; // 2、定位方法执行,获取执行结果
Object result = new Object();
MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
SqlCommondType sqlCommondType = mappedStatement.getSqlCommondType();
switch (sqlCommondType){
case INSERT:
result = insert(statementId,args);
break;
case DELETE:
result = delete(statementId,args);
break;
case UPDATE:
result = update(statementId,args);
break;
case SELECT:
// 获取被调用方法的返回值
Type returnType = method.getGenericReturnType();
if (returnType instanceof ParameterizedType){
result = selectList(statementId, args);
}else{
result = selectOne(statementId,args);
}
break;
default:
throw new Exception("statementId:"+statementId+",操作类型:"+sqlCommondType+"有误");
}
return result;
}
});
return (T) o;
}
}修改Executor、SimpleExecutor
package com.rangers.persistent.executor; import com.rangers.persistent.config.pojo.Configuration;
import com.rangers.persistent.config.pojo.MappedStatement; import java.sql.SQLException;
import java.util.List; /**
* @Author Rangers
* @Description
* @Date 2021-03-04
**/
public interface Executor { <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object...param) throws Exception; Integer insert(Configuration configuration, MappedStatement mappedStatement, Object...param) throws Exception; Integer update(Configuration configuration, MappedStatement mappedStatement, Object...param) throws Exception; Integer delete(Configuration configuration, MappedStatement mappedStatement, Object...param) throws Exception; void close() throws SQLException;
}
package com.rangers.persistent.executor; import com.mchange.v2.c3p0.impl.NewProxyPreparedStatement;
import com.rangers.persistent.config.pojo.Configuration;
import com.rangers.persistent.config.pojo.MappedStatement;
import com.rangers.persistent.utils.GenericTokenParser;
import com.rangers.persistent.utils.ParameterMapping;
import com.rangers.persistent.utils.ParameterMappingTokenHandler;
import org.apache.commons.collections.CollectionUtils; import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List; /**
* @Author Rangers
* @Description
* @Date 2021-03-04
**/
public class SimpleExecutor implements Executor { private Connection connnection = null; @Override
public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception {
PreparedStatement preparedStatement = this.getPreparedStatement(configuration, mappedStatement, params); // 5、执行SQL语句
ResultSet resultSet = preparedStatement.executeQuery(); // 6、封装返回结果集
// 获取SQL的执行结果类型
String resultType = mappedStatement.getResultType();
Class<?> resultTypeClazz = getClassType(resultType);
List<E> results = new ArrayList<>();
// 遍历封装结果集为返回值类型
while (resultSet.next()) {
// 获取结果集的元数据
ResultSetMetaData metaData = resultSet.getMetaData();
E e = (E) resultTypeClazz.newInstance();
if (metaData.getColumnCount() > 0) {
for (int i = 1; i <= metaData.getColumnCount(); i++) {
// 字段名称
String columnName = metaData.getColumnName(i);
// 字段值
Object columnValue = resultSet.getObject(columnName); // 使用反射或者内省,根据数据库表与实体的对应关系,完成结果集封装
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName,resultTypeClazz);
Method writeMethod = propertyDescriptor.getWriteMethod();
writeMethod.invoke(e,columnValue);
}
}
results.add(e);
}
return results;
} @Override
public Integer insert(Configuration configuration, MappedStatement mappedStatement, Object... param) throws Exception {
return this.update(configuration,mappedStatement,param);
} @Override
public Integer update(Configuration configuration, MappedStatement mappedStatement, Object... param) throws Exception {
PreparedStatement preparedStatement = this.getPreparedStatement(configuration, mappedStatement, param);
return preparedStatement.executeUpdate();
} @Override
public Integer delete(Configuration configuration, MappedStatement mappedStatement, Object... param) throws Exception {
return this.update(configuration,mappedStatement,param);
} private PreparedStatement getPreparedStatement(Configuration configuration, MappedStatement mappedStatement, Object[] params) throws SQLException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
// 1、获取数据库链接
connnection = configuration.getDataSource().getConnection();
// 2、解析SQL语句中的#/$,及参数列表,封装为BoundSql对象
BoundSql boundSql = getBoundSQL(mappedStatement.getSql());
// 替换后的SQL语句
String finalSql = boundSql.getSqlText();
// 3、获取PreparedStatement对象
PreparedStatement preparedStatement = connnection.prepareStatement(finalSql); // 4、设置参数
// 获取传入参数类型
String parameterType = mappedStatement.getParamterType();
Class<?> parameterTypeClazz = getClassType(parameterType);
// 获取SQL语句中需要替换的的参数列表
List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
if (CollectionUtils.isNotEmpty(parameterMappingList)) {
for (int i = 0; i < parameterMappingList.size(); i++) {
ParameterMapping parameterMapping = parameterMappingList.get(i);
// SQL语句中解析出的占位参数名称
String content = parameterMapping.getContent(); // 利用反射从入参列表中获取数据
Field declaredField = parameterTypeClazz.getDeclaredField(content);
// 设置暴力访问
declaredField.setAccessible(true);
// 此处默认传入参数类型为对象
Object param = declaredField.get(params[0]);
preparedStatement.setObject(i + 1, param);
}
}
// 打印执行语句
this.printSql(preparedStatement); return preparedStatement;
} private void printSql(PreparedStatement preparedStatement) throws NoSuchFieldException, IllegalAccessException {
NewProxyPreparedStatement tmpPs = (NewProxyPreparedStatement) preparedStatement;
Field inner = preparedStatement.getClass().getDeclaredField("inner");
inner.setAccessible(true);
String sqlLog = inner.get(tmpPs).toString();
System.out.println("执行SQL:"+sqlLog.substring(sqlLog.lastIndexOf(":")+1));
} private Class<?> getClassType(String type) throws ClassNotFoundException {
if (type != null && type!="") {
return Class.forName(type);
}
return null;
} private BoundSql getBoundSQL(String sql) {
ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", parameterMappingTokenHandler);
String parseSql = genericTokenParser.parse(sql);
List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();
return new BoundSql(parseSql, parameterMappings);
} @Override
public void close() throws SQLException {
connnection.close();
}
}
拆分测试类直接获取与动态代理
package com.rangers.mypersistent; import com.rangers.entity.User;
import com.rangers.persistent.sqlSession.SqlSession;
import com.rangers.persistent.sqlSessionFactory.SqlSessionFactory;
import com.rangers.persistent.sqlSessionFactory.SqlSessionFactoryBuilder;
import com.rangers.persistent.utils.Resources;
import org.dom4j.DocumentException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test; import java.beans.PropertyVetoException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.List; /**
* @Author Rangers
* @Description
* @Date 2021-03-04
**/
public class MyPersistentTest { private SqlSession sqlSession; @Before
public void before() throws PropertyVetoException, DocumentException {
// 加载配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 解析XML文件为对象,构造SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
sqlSession = sqlSessionFactory.openSession();
} @Test
public void selectList() throws Exception {
List<User> users = sqlSession.selectList("com.rangers.IUserDao.selectList", null);
System.out.println(users.toString());;
} @Test
public void selectOne() throws Exception {
User user = new User();
user.setId(2);
user.setName("莉莉");
User result = sqlSession.selectOne("com.rangers.IUserDao.selectOne", user);
System.out.println(result.toString());
} @Test
public void insert() throws Exception {
User user = new User();
user.setId(3);
user.setName("bug");
user.setAddress("北京");
boolean insertFlag = sqlSession.insert("com.rangers.IUserDao.insert",user) > 0;
System.out.println("新增标识:"+insertFlag);
} @Test
public void update() throws Exception {
User user = new User();
user.setId(3);
user.setName("虫子");
user.setAddress("北京");
boolean updateFlag = sqlSession.update("com.rangers.IUserDao.update", user)>0;
System.out.println("修改标识:"+updateFlag);
} @Test
public void delete() throws Exception {
User user = new User();
user.setId(3);
boolean updateFlag = sqlSession.update("com.rangers.IUserDao.delete", user)>0;
System.out.println("删除标识:"+updateFlag);
} @After
public void after() throws SQLException {
sqlSession.close();
}
}
package com.rangers.mypersistent; import com.rangers.IUserDao;
import com.rangers.entity.User;
import com.rangers.persistent.sqlSession.SqlSession;
import com.rangers.persistent.sqlSessionFactory.SqlSessionFactory;
import com.rangers.persistent.sqlSessionFactory.SqlSessionFactoryBuilder;
import com.rangers.persistent.utils.Resources;
import org.dom4j.DocumentException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test; import java.beans.PropertyVetoException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.List; /**
* @Author Rangers
* @Description
* @Date 2021-03-08
**/
public class MapperTest { private SqlSession sqlSession; @Before
public void before() throws PropertyVetoException, DocumentException {
// 加载配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 解析XML文件为对象,构造SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
sqlSession = sqlSessionFactory.openSession();
} @Test
public void mapperSelectOne() throws Exception {
User userParam = new User();
userParam.setId(2);
userParam.setName("莉莉");
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
User result = userDao.selectOne(userParam);
System.out.println(result.toString());
} @Test
public void mapperSelectAll() throws Exception {
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
List<User> result = userDao.selectList();
System.out.println(result.toString());
} @Test
public void mapperInsert() throws Exception {
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
User user = new User();
user.setId(3);
user.setName("bug");
user.setAddress("北京");
boolean insertFlag = userDao.insert(user) > 0;
System.out.println("新增标识:"+insertFlag);
} @Test
public void mapperUpdate() throws Exception {
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
User user = new User();
user.setId(3);
user.setName("虫子");
user.setAddress("北京");
boolean updateFlag = userDao.update(user) > 0;
System.out.println("修改标识:"+updateFlag);
} @Test
public void mapperDelete() throws Exception {
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
User user = new User();
user.setId(3);
boolean deleteFlag = userDao.delete(user) > 0;
System.out.println("删除标识:"+deleteFlag);
} @After
public void after() throws SQLException {
sqlSession.close();
}
}
最新文章
- UITableViewCell定制
- 经验分享:Xcode 创建.a和framework静态库【转】
- extjs文件上传
- 九度OJ 1209 最小邮票数 -- 动态规划
- C++默认构造函数的一点说明
- redis-cli的一些有趣也很有用的功能
- Spring XML文件配置
- 简单的词法设计——DFA模拟程序
- qhfl-2 ContentType组件
- python全栈开发day37-html
- java 集合框架 Java集合&;List的实现
- Cross-site request forgery 跨站请求伪造
- 【洛谷P2661】信息传递
- 数据访问:Implementing Efficient Transactions
- 微信小程序 - 上拉加载更多组件
- 安装MySQL-python报错:_mysql.c(42) : fatal error C1083: Cannot open include file: &#39;config-win.h&#39;: No such file or directory或者 build\lib.win-amd64-2.7\_mysql.pyd : fatal error LNK1120: 56 unresolved externa
- sell 项目 订单表 设计 及 创建
- [转] Spring4.3.x 浅析xml配置的解析过程(6)——解析context命名空间之property-placeholder和property-override标签
- (转)Kangle配置文件
- 在windows上搭建C语言开发环境——借助eclipse和MinGW
热门文章
- Codeforces Round #654 (Div. 2) D. Grid-00100 (构造)
- Python3.9.1中如何使用match方法?
- 国产网络损伤仪SandStorm -- 为什么数据流还是走Bypass链路?
- ssh配置方面小实验①
- Git使用指南(上)
- 用python写的一个自动卸载python包的脚本
- Linux Centos7发送QQ邮件
- WebVR &; CSS 3D &; WebGL
- modal over table bug
- ts 在Function上创建静态属性和方法