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(); } }