MyBatis(三):自定义持久层框架实现
代码已上传至码云:https://gitee.com/rangers-sun/mybatis
新建Maven工程
架构端MyPersistent、使用端MyPersistentTest,使用端引入架构端Maven坐标
MyPersistentTest使用端配置
新增依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
<dependency>
<groupId>com.rangers</groupId>
<artifactId>MyPersistent</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency> <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
</dependency>
新建实体类User
package com.rangers.entity; /**
* @Author Rangers
* @Description
* @Date 2021-03-04
**/
public class User { private int id; private String name; private String address; @Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", address='" + address + '\'' +
'}';
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getAddress() {
return address;
} public void setAddress(String address) {
this.address = address;
}
}
定义查询数据接口IUserDao
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/8 10:43 上午
* @Return: java.util.List<com.rangers.entity.User>
**/
public List<User> selectList(); /**
* @Author Rangers
* @Description 根据条件查询单个用户信息
* @Date 2021/3/8 10:43 上午
* @Param user:
* @Return: com.rangers.entity.User
**/
public User selectOne(User user) ;
}配置UserMapper.xml
<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>
</mapper>
配置SqlMapConfig.xml,引入UserMapper.xml的路径
<configuration>
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mybatis"></property>
<property name="user" value="root"></property>
<property name="password" value="111222"></property> <mapper resource="UserMapper.xml"/>
</configuration>
MyPersistent架构端
新增依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
新建工具类Resources,加载XML文件为输入流
package com.rangers.persistent.utils; import java.io.InputStream; /**
* @Author Rangers
* @Description
* @Date 2021-03-04
**/
public class Resources {
/**
* @Author: Rangers
* @Description: 加载配置文件
* @Date: 2021/3/7 4:50 下午
* @Param path:
* @Return: java.io.InputStream
**/
public static InputStream getResourceAsStream(String path){
return Resources.class.getClassLoader().getResourceAsStream(path);
}
}
新建实体MappedStatement类,对应XxMapper中的标签元素
package com.rangers.persistent.config.pojo; /**
* @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; 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;
}
}
新建实体Configuration类,对应SqlMapConfig.xml中的元素
package com.rangers.persistent.config.pojo; import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map; /**
* @Author Rangers
* @Description 对应SqlMapConfig.xml中的标签
* @Date 2021-03-04
**/
public class Configuration { // 数据源信息
private DataSource dataSource; // 存放Mapper中的所有标签 key为namespace+"."+id
private Map<String,MappedStatement> mappedStatementMap = new HashMap<>(); public DataSource getDataSource() {
return dataSource;
} public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
} public Map<String, MappedStatement> getMappedStatementMap() {
return mappedStatementMap;
} public void setMappedStatementMap(Map<String, MappedStatement> mappedStatementMap) {
this.mappedStatementMap = mappedStatementMap;
}
}
新建XmlConfigurationBuilder类,解析SqlMapConfig.xml
package com.rangers.persistent.config; import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.rangers.persistent.utils.Resources;
import com.rangers.persistent.config.pojo.Configuration;
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.beans.PropertyVetoException;
import java.io.InputStream;
import java.util.List;
import java.util.Properties; /**
* @Author Rangers
* @Description 解析SqlMapConfig.xml
* @Date 2021-03-04
**/
public class XmlConfigurationBuilder {
private Configuration configuration; public XmlConfigurationBuilder(Configuration configuration) {
this.configuration = configuration;
} public Configuration parseConfiguration(InputStream inputStream) throws PropertyVetoException,DocumentException {
Document document = new SAXReader().read(inputStream);
Element rootElement = document.getRootElement();
// 数据库配置信息进configuration对象
this.parseDatasource(rootElement);
// 将Mapper读入configuration对象
this.parseMappers(rootElement);
return configuration;
} private void parseMappers(Element rootElement) {
XmlMapperBuilder xmlMapperBuilder = new XmlMapperBuilder(configuration);
List<Element> mapperElements = rootElement.selectNodes("//mapper");
if (CollectionUtils.isNotEmpty(mapperElements)){
mapperElements.forEach(x->{
// 获取单个Mapper路径
String mapperPath = x.attributeValue("resource");
// 获取xml文件
InputStream mapperInputStream = Resources.getResourceAsStream(mapperPath);
// 解析xml文件存入configuration对象中的mappedStatementMap中
xmlMapperBuilder.parse(mapperInputStream);
});
}
} private void parseDatasource(Element rootElement) throws PropertyVetoException {
List<Element> propertyElements = rootElement.selectNodes("//property"); Properties properties = new Properties();
if (CollectionUtils.isNotEmpty(propertyElements)) {
propertyElements.forEach(x->{
properties.setProperty(x.attributeValue("name"),x.attributeValue("value"));
});
} ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setDriverClass(properties.getProperty("driverClass"));
comboPooledDataSource.setJdbcUrl(properties.getProperty("jdbcUrl"));
comboPooledDataSource.setUser(properties.getProperty("user"));
comboPooledDataSource.setPassword(properties.getProperty("password")); configuration.setDataSource(comboPooledDataSource);
}
}
新建XmlMapperBuilder解析XxMapper.xml
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.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> selectElements = rootElement.selectNodes("select");
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"); MappedStatement mappedStatement = new MappedStatement();
mappedStatement.setId(id);
mappedStatement.setSql(sql);
mappedStatement.setParamterType(parameterType);
mappedStatement.setResultType(resultType);
configuration.getMappedStatementMap().put(namespace+"."+id,mappedStatement);
});
}
} }
新建SqlSessionFactory、DefaultSqlSessionFactory、SqlSessionFactoryBuilder类生产SqlSessionFactory
package com.rangers.persistent.sqlSessionFactory; import com.rangers.persistent.sqlSession.SqlSession; /**
* @Author Rangers
* @Description
* @Date 2021-03-04
**/
public interface SqlSessionFactory {
SqlSession openSession();
}
package com.rangers.persistent.sqlSessionFactory; import com.rangers.persistent.config.pojo.Configuration;
import com.rangers.persistent.sqlSession.DefaultSqlSession;
import com.rangers.persistent.sqlSession.SqlSession; /**
* @Author Rangers
* @Description
* @Date 2021-03-04
**/
public class DefaultSqlSessionFactory implements SqlSessionFactory{ private Configuration configuration; public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
} @Override
public SqlSession openSession() {
return new DefaultSqlSession(configuration);
}
}
package com.rangers.persistent.sqlSessionFactory; import com.rangers.persistent.config.XmlConfigurationBuilder;
import com.rangers.persistent.config.pojo.Configuration;
import org.dom4j.DocumentException; import java.beans.PropertyVetoException;
import java.io.InputStream; /**
* @Author Rangers
* @Description
* @Date 2021-03-04
**/
public class SqlSessionFactoryBuilder {
private Configuration configuration; public SqlSessionFactoryBuilder() {
this.configuration = new Configuration();
} public SqlSessionFactory build(InputStream inputStream) throws PropertyVetoException, DocumentException {
XmlConfigurationBuilder xmlConfigurationBuilder = new XmlConfigurationBuilder(configuration);
// 将XML文件分装为Configuration/MappedStatement对象中
Configuration configuration = xmlConfigurationBuilder.parseConfiguration(inputStream);
return new DefaultSqlSessionFactory(configuration);
}
}
新建SqlSession、DefaultSqlSession
package com.rangers.persistent.sqlSession; import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
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 IllegalAccessException, IntrospectionException, InstantiationException, SQLException, InvocationTargetException, NoSuchFieldException, ClassNotFoundException; <T> T selectOne(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.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.beans.IntrospectionException;
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 IllegalAccessException, IntrospectionException, InstantiationException, SQLException, InvocationTargetException, NoSuchFieldException, ClassNotFoundException {
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 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();
// 获取被调用方法的返回值
Type returnType = method.getGenericReturnType();
if (returnType instanceof ParameterizedType){
result = selectList(statementId, args);
}else{
result = selectOne(statementId,args);
}
return result;
}
});
return (T) o;
}
}新建Executor、SimpleExecutor、BoundSql
package com.rangers.persistent.executor; import com.rangers.persistent.config.pojo.Configuration;
import com.rangers.persistent.config.pojo.MappedStatement; import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
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 SQLException, NoSuchFieldException, IllegalAccessException, IntrospectionException, InvocationTargetException, InstantiationException, ClassNotFoundException; 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.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; /**
* @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 SQLException, NoSuchFieldException, IllegalAccessException, IntrospectionException, InvocationTargetException, InstantiationException, ClassNotFoundException {
// 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); // 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;
} 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.persistent.executor; import com.rangers.persistent.utils.ParameterMapping; import java.util.ArrayList;
import java.util.List; public class BoundSql { private String sqlText; //解析过后的sql private List<ParameterMapping> parameterMappingList = new ArrayList<>(); public BoundSql(String sqlText, List<ParameterMapping> parameterMappingList) {
this.sqlText = sqlText;
this.parameterMappingList = parameterMappingList;
} public String getSqlText() {
return sqlText;
} public void setSqlText(String sqlText) {
this.sqlText = sqlText;
} public List<ParameterMapping> getParameterMappingList() {
return parameterMappingList;
} public void setParameterMappingList(List<ParameterMapping> parameterMappingList) {
this.parameterMappingList = parameterMappingList;
}
}
新增SQL解析工具类ParameterMapping、GenericTokenParser、TokenHandler、ParameterMappingTokenHandler
package com.rangers.persistent.utils; public class ParameterMapping { private String content; public ParameterMapping(String content) {
this.content = content;
} public String getContent() {
return content;
} public void setContent(String content) {
this.content = content;
}
}
package com.rangers.persistent.utils; /**
* @author Clinton Begin
*/
public class GenericTokenParser { private final String openToken; //开始标记
private final String closeToken; //结束标记
private final TokenHandler handler; //标记处理器 public GenericTokenParser(String openToken, String closeToken, TokenHandler handler) {
this.openToken = openToken;
this.closeToken = closeToken;
this.handler = handler;
} /**
* 解析${}和#{}
* @param text
* @return
* 该方法主要实现了配置文件、脚本等片段中占位符的解析、处理工作,并返回最终需要的数据。
* 其中,解析工作由该方法完成,处理工作是由处理器handler的handleToken()方法来实现
*/
public String parse(String text) {
// 验证参数问题,如果是null,就返回空字符串。
if (text == null || text.isEmpty()) {
return "";
} // 下面继续验证是否包含开始标签,如果不包含,默认不是占位符,直接原样返回即可,否则继续执行。
int start = text.indexOf(openToken, 0);
if (start == -1) {
return text;
} // 把text转成字符数组src,并且定义默认偏移量offset=0、存储最终需要返回字符串的变量builder,
// text变量中占位符对应的变量名expression。判断start是否大于-1(即text中是否存在openToken),如果存在就执行下面代码
char[] src = text.toCharArray();
int offset = 0;
final StringBuilder builder = new StringBuilder();
StringBuilder expression = null;
while (start > -1) {
// 判断如果开始标记前如果有转义字符,就不作为openToken进行处理,否则继续处理
if (start > 0 && src[start - 1] == '\\') {
builder.append(src, offset, start - offset - 1).append(openToken);
offset = start + openToken.length();
} else {
//重置expression变量,避免空指针或者老数据干扰。
if (expression == null) {
expression = new StringBuilder();
} else {
expression.setLength(0);
}
builder.append(src, offset, start - offset);
offset = start + openToken.length();
int end = text.indexOf(closeToken, offset);
while (end > -1) {////存在结束标记时
if (end > offset && src[end - 1] == '\\') {//如果结束标记前面有转义字符时
// this close token is escaped. remove the backslash and continue.
expression.append(src, offset, end - offset - 1).append(closeToken);
offset = end + closeToken.length();
end = text.indexOf(closeToken, offset);
} else {//不存在转义字符,即需要作为参数进行处理
expression.append(src, offset, end - offset);
offset = end + closeToken.length();
break;
}
}
if (end == -1) {
// close token was not found.
builder.append(src, start, src.length - start);
offset = src.length;
} else {
//首先根据参数的key(即expression)进行参数处理,返回?作为占位符
builder.append(handler.handleToken(expression.toString()));
offset = end + closeToken.length();
}
}
start = text.indexOf(openToken, offset);
}
if (offset < src.length) {
builder.append(src, offset, src.length - offset);
}
return builder.toString();
}
}
package com.rangers.persistent.utils; /**
* @author Clinton Begin
*/
public interface TokenHandler {
String handleToken(String content);
}
package com.rangers.persistent.utils; import java.util.ArrayList;
import java.util.List; public class ParameterMappingTokenHandler implements TokenHandler {
private List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>(); // context是参数名称 #{id} #{username} @Override
public String handleToken(String content) {
parameterMappings.add(buildParameterMapping(content));
return "?";
} private ParameterMapping buildParameterMapping(String content) {
ParameterMapping parameterMapping = new ParameterMapping(content);
return parameterMapping;
} public List<ParameterMapping> getParameterMappings() {
return parameterMappings;
} public void setParameterMappings(List<ParameterMapping> parameterMappings) {
this.parameterMappings = parameterMappings;
} }
新建测试类MypersistentTest
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-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.entity.User.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.entity.User.selectOne", user);
System.out.println(result.toString());
} @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());
} @After
public void after() throws SQLException {
sqlSession.close();
}
}
MyBatis(三):自定义持久层框架实现的更多相关文章
- MyBatis(四):自定义持久层框架优化
本文所有代码已上传至码云:https://gitee.com/rangers-sun/mybatis 修改IUserDao.UserMapper.xml package com.rangers; im ...
- MyBatis(二):自定义持久层框架思路分析
使用端 引入架构端Maven依赖 SqlMapConfig.xml-数据库配置信息(数据库连接jar名称.连接URL.用户名.密码),引入Mapper.xml的路径 XxMapper.xml-SQL配 ...
- Mybatis学习之自定义持久层框架(三) 自定义持久层框架:读取并解析配置文件
前言 前两篇文章分别讲解了JDBC和Mybatis的基本知识,以及自定义持久层框架的设计思路,从这篇文章开始,我们正式来实现一个持久层框架. 新建一个项目 首先我们新建一个maven项目,将其命名为I ...
- Java工程师高薪训练营-第一阶段 开源框架源码解析-模块一 持久层框架涉及实现及MyBatis源码分析-任务一:自定义持久层框架
目录 任务一:自定义持久层框架 1.1 JDBC回顾及问题分析 1.2 自定义持久层框架思路分析 1.3 IPersistence_Test编写 1.3.1 XXXMapper.xml详解 1.3.2 ...
- 【笔记】拉勾Java工程师高薪训练营-第一阶段 开源框架源码解析-模块一 持久层框架涉及实现及MyBatis源码分析-任务一:自定义持久层框架
以下笔记是我看完视频之后总结整理的,部分较为基础的知识点也做了补充,如有问题欢迎沟通. 目录 任务一:自定义持久层框架 1.1 JDBC回顾及问题分析 1.2 自定义持久层框架思路分析 1.3 IPe ...
- Mybatis学习之自定义持久层框架(六) 自定义持久层框架:完善CRUD方法并进行测试
前言 没想到会等到半年以后才来写这篇文章,我已经不记得当初自己想要在这篇文章中写什么了,还好有一些零散的笔记留着,就对照着上一篇文章及零散的笔记,把内容给补充完吧. 完善CRUD方法 完善Defaul ...
- Mybatis学习之自定义持久层框架(二) 自定义持久层框架设计思路
前言 上一篇文章讲到了JDBC的基本用法及其问题所在,并提出了使用Mybatis的好处,那么今天这篇文章就来说一下该如何设计一个类似Mybatis这样的持久层框架(暂时只讲思路,具体的代码编写工作从下 ...
- Mybatis学习之自定义持久层框架(七) 自定义持久层框架优化
前言 接上文,这里只是出于强迫症,凭借着半年前的笔记来把之前没写完的文章写完,这里是最后一篇了. 前面自定义的持久层框架存在的问题 Dao层若使用实现类,会存在代码重复,整个操作的过程模版重复(加载配 ...
- Mybatis学习之自定义持久层框架(一) 为什么要用框架而不直接用JDBC?
前言 说起Mybatis,相信大家都不会感到陌生,它是一款优秀的持久层框架,应用于java后端开发中,为客户端程序提供访问数据库的接口. 我们都知道,JDBC是Java语言中用来规范客户端程序如何来访 ...
随机推荐
- 字典树 && 例题 Xor Sum HDU - 4825 (板子)
一.字典树描述:Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优 ...
- c文件二进制读取写入文件、c语言实现二进制(01)转化成txt格式文本、c读取文件名可变
c语言实现二进制(01)转化成txt格式文本: 下面的程序只能实现ascall对应字符转换,如果文件内出现中文字符,则会出现错误. 本程序要自己创建个文本格式的输入文件a1.txt,编译后能将文本文件 ...
- Educational Codeforces Round 56 (Rated for Div. 2) D. Beautiful Graph (二分图染色)
题意:有\(n\)个点,\(m\)条边的无向图,可以给每个点赋点权\({1,2,3}\),使得每个点连的奇偶不同,问有多少种方案,答案对\(998244353\)取模. 题解:要使得每个点所连的奇偶不 ...
- Linux系统编程【2】——编写who命令
学到的知识点 通过实现who命令,学到了: 1.使用man命令寻找相关信息 2.基于文件编程 3.体会到c库函数与系统调用的不同 4.加深对缓冲技术的理解 who命令的作用 who命令的使用 在控制终 ...
- Python小练习批量爬取下载歌曲
import requests import os headers={ 'Cookie': '_ga=GA1.2.701818100.1612092981; _gid=GA1.2.748589379. ...
- 1.初识Redis
作者 微信:tangy8080 电子邮箱:914661180@qq.com 更新时间:2019-08-14 20:35:36 星期三 欢迎您订阅和分享我的订阅号,订阅号内会不定期分享一些我自己学习过程 ...
- python3 anaconda 安装pyhook3 pythoncom(pywin32)
为什么不安装pyhook 1.pyhook不支持python3 2.网络上有一些方法下载pyhook的whl然后pip安装到python3,可以运行,但是会因为编码问题导致移动到窗口标题含有非ASCI ...
- 计蒜客 第四场 C 商汤科技的行人检测(中等)平面几何好题
商汤科技近日推出的 SenseVideo 能够对视频监控中的对象进行识别与分析,包括行人检测等.在行人检测问题中,最重要的就是对行人移动的检测.由于往往是在视频监控数据中检测行人,我们将图像上的行人抽 ...
- 后Low Code时代:聚焦和突破
很多人都不想被贴上标签,我曾经也一样.觉得青春不能被定义,人也不能被分类.但随着学习和工作的变迁,慢慢开始发现标签也是一种名片效应. 比如一个做汽车销售的朋友,他就对BMW的车型非常熟悉,可以说是懂车 ...
- Shell 编程快速上手
Shell 编程快速上手 test.sh #!/bin/sh cd ~ mkdir shell_tut cd shell_tut for ((i=0; i<10; i++)); do touch ...