本文所有代码已上传至码云: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(); } }