一、自定义持久层框架

1.分析JDBC操作问题

package com.cookie.jdbc.test;

import com.cookie.jdbc.domain.User;
import java.sql.*;

public class TestJdbc {

    public static void main(String[] args) {

        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            // 加载数据库驱动
            Class.forName("com.mysql.jdbc.Driver");
            // 通过驱动管理类获取数据库链接
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?characterEncoding=utf-8", "root", "123456");
            // 定义sql语句?表示占位符
            String sql = "select * from user where username = ?";
            // 获取预处理statement
            preparedStatement = connection.prepareStatement(sql);
            // 设置参数,第⼀个参数为sql语句中参数的序号(从1开始),第⼆个参数为设置的参数值
            preparedStatement.setString(1,"tom");
            // 向数据库发出sql执⾏查询,查询出结果集
            resultSet = preparedStatement.executeQuery();
            while(resultSet.next()){
                User user = new User();
                int id = resultSet.getInt("id");
                String username = resultSet.getString("username");
                // 封装User
                user.setId(id);
                user.setUsername(username);
                System.out.println(user);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //释放资源
            if (resultSet != null){
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (preparedStatement != null){
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null){
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

sql:

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL,
  `password` varchar(50) DEFAULT NULL,
  `birthday` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'lucy', '123', '2019-12-12');
INSERT INTO `user` VALUES ('2', 'tom','123', '2019-12-12');

JDBC问题总结:
原始jdbc开发存在的问题如下:
1、 数据库连接创建、释放频繁造成系统资源浪费,从而影响系统性能。
2、 Sql语句在代码中硬编码,造成代码不易维护,实际应用中sql变化的可能较大, sql变动需要改变 java代码。
3、 使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。
4、 对结果集解析存在硬编码(查询列名), sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便

2.问题解决思路

①使用数据库连接池初始化连接资源
②将sql语句抽取到xml配置文件中
③使用反射、内省等底层技术,自动将实体与表进行属性与字段的自动映射

3.自定义框架设计

3.1 使用端:

  • 引入持久层框架的jar包
  • 提供两部分配置信息,数据库信息、sql配置信息(sql语句、参数类型、返回值类型)
  • 提供核心配置文件:①sqlMapConfig.xml :存放数据源信息,引入mapper.xml,存放mapper.xml的全路径②Mapper.xml:sql语句的配置文件信息

3.2 框架端:

  1. 加载读取配置文件:根据配置文件的路径加载文件成字节输入流,存储在内存中

创建Resources类,方法:InputStream getResourceAsSteam(String path)

  1. 创建2个javaBean,存放的是配置文件解析出来的内容
    1. Configuration:核心配置类,存放sqlMapConfig.xml解析出来的内容
    2. MappedStatement:映射配置类,存放Mapper.xml解析出来的内容
  2. 解析配置文件:dom4j
    1. 创建类:SqlSessionFactoryBuilder 方法:build(InputStream in)
    2. 1.使用dom4j解析配置文件,将解析出来的内容封装到容器对象中
    3. 2.创建SqlSessionFactory 对象,产生sqlSession:会话对象(工厂模式)
  3. 创建SqlSessionFactory 接口及实现类DefaultSqlSessionFactory
    1. 1.openSession(): 生产sqlSession
  4. 创建sqlSession接口及实现类DefaultSqlSession
    1. 定义对数据库的crud操作:selectList() selectOne() update() delete()
  5. 创建Executor接口及实现类SimpleExecutor实现类
    1. query(Configuration,MappedStatement,Object…param):执行JDBC代码

4. 自定义框架实现

在使用端项目中创建配置配置文件创建 sqlMapConfig.xml

<configuration>
    <dataSource>
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123456"></property>
    </dataSource>


    <!--存放mapper.xml的全路径-->
    <mapper resource = "UserMapper.xml"></mapper>
</configuration>
<mapper namespace="user">
    <!--sql的唯一标识:namespace.id组成 :statementId -->
    <select id="selectList" resultType="com.cookie.pojo.User">
        select * from user
    </select>
    <!--多个参数传递封装对象-->
    <select id="selectOne" resultType="com.cookie.pojo.User" paramType="com.cookie.pojo.User">
        select * from user where id = #{id} and username = #{username}
    </select>
</mapper>
package com.cookie.pojo;

public class User {

    private Integer id;
    private String username;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                '}';
    }
}

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>mybatis</artifactId>
        <groupId>com.cookie</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>simple-mybatis-test</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.cookie</groupId>
            <artifactId>simple-mybatis</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>


</project>
package com.cookie.test;

import com.cookie.io.Resources;
import com.cookie.pojo.User;
import com.cookie.sqlSession.SqlSession;
import com.cookie.sqlSession.SqlSessionFactory;
import com.cookie.sqlSession.SqlSessionFactoryBuilder;
import org.dom4j.DocumentException;
import org.junit.Test;

import java.beans.IntrospectionException;
import java.beans.PropertyVetoException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;

public class SimpleTest {
    @Test
    public void test() throws DocumentException, PropertyVetoException, ClassNotFoundException, IllegalAccessException, IntrospectionException, InstantiationException, SQLException, InvocationTargetException, NoSuchFieldException {
        InputStream inputStream = Resources.getResourceAsSteam("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        User user = new User();
        user.setId(2);
        user.setUsername("tom");
        User u = sqlSession.selectOne("user.selectOne", user);
        System.out.println(u);
    }
}

再创建一个Maven子工程并且导入需要用到的依赖坐标

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <parent>
    <artifactId>mybatis</artifactId>
    <groupId>com.cookie</groupId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <modelVersion>4.0.0</modelVersion>

  <artifactId>simple-mybatis</artifactId>


  <dependencies>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.17</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.10</version>
    </dependency>
    <dependency>
      <groupId>dom4j</groupId>
      <artifactId>dom4j</artifactId>
      <version>1.6.1</version>
    </dependency>
    <dependency>
      <groupId>jaxen</groupId>
      <artifactId>jaxen</artifactId>
      <version>1.1.6</version>
    </dependency>
  </dependencies>


  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>7</source>
          <target>7</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>
package com.cookie.pojo;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

public class Configuration {
    private DataSource dataSource;
    private Map<String,MapperStatement> map = new HashMap<>();

    public DataSource getDataSource() {
        return dataSource;
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public Map<String, MapperStatement> getMap() {
        return map;
    }

    public void setMap(Map<String, MapperStatement> map) {
        this.map = map;
    }
}

package com.cookie.pojo;

public class MapperStatement {

    //id标识
    private String id;
    //返回值
    private String resultType;
    //参数值类型
    private String paramType;
    //sql语句
    private String sql;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getResultType() {
        return resultType;
    }

    public void setResultType(String resultType) {
        this.resultType = resultType;
    }

    public String getParamType() {
        return paramType;
    }

    public void setParamType(String paramType) {
        this.paramType = paramType;
    }

    public String getSql() {
        return sql;
    }

    public void setSql(String sql) {
        this.sql = sql;
    }
}

package com.cookie.io;

import java.io.InputStream;

public class Resources {
    public static InputStream getResourceAsSteam(String path){
        //根据配置文件的路径将配置文件加载成字节输入流
        InputStream inputStream = Resources.class.getClassLoader().getResourceAsStream(path);
        return inputStream;
    }
}

package com.cookie.sqlSession;

import com.cookie.config.XMLConfigBuilder;
import com.cookie.pojo.Configuration;
import org.dom4j.DocumentException;

import java.beans.PropertyVetoException;
import java.io.InputStream;

public class SqlSessionFactoryBuilder {


    public SqlSessionFactory build(InputStream in) throws PropertyVetoException, DocumentException, ClassNotFoundException {

        //第一,使用dom4j解析配置文件,将解析出来的内容封装到Configuration中
        XMLConfigBuilder xmlConfigBuilder = new XMLConfigBuilder();
        Configuration configuration = xmlConfigBuilder.parseConfig(in);

        //第二、创建sqlSessionFactory对象 工厂类:生产sqlSession:会话对象
        DefaultSqlSessionFactory defaultSqlSessionFactory = new DefaultSqlSessionFactory(configuration);
        return defaultSqlSessionFactory;
    }



}

package com.cookie.config;

import com.cookie.io.Resources;
import com.cookie.pojo.Configuration;
import com.mchange.v2.c3p0.ComboPooledDataSource;
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;


public class XMLConfigBuilder {


    private Configuration configuration;


    public XMLConfigBuilder() {

        this.configuration = new Configuration();
    }

    /**
     * 该方法就是将配置文件进行解析,封装Configuration
     * @param inputStream
     * @return
     */
    public Configuration parseConfig(InputStream inputStream) throws DocumentException, PropertyVetoException, ClassNotFoundException {

        Document document = new SAXReader().read(inputStream);
        Element rootElement = document.getRootElement();
        List<Element> list = rootElement.selectNodes("//property");
        Properties properties = new Properties();
        for (Element element : list) {
            String name = element.attributeValue("name");
            String value = element.attributeValue("value");
            properties.setProperty(name,value);
        }
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        comboPooledDataSource.setDriverClass(properties.getProperty("driverClass"));
        comboPooledDataSource.setJdbcUrl(properties.getProperty("jdbcUrl"));
        comboPooledDataSource.setUser(properties.getProperty("username"));
        comboPooledDataSource.setPassword(properties.getProperty("password"));

        configuration.setDataSource(comboPooledDataSource);

        List<Element> mapperElements = rootElement.selectNodes("//mapper");
        XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(configuration);
        for (Element mapperElement : mapperElements) {
            String resource = mapperElement.attributeValue("resource");
            InputStream resourceAsSteam = Resources.getResourceAsSteam(resource);
            xmlMapperBuilder.parse(resourceAsSteam);
        }


        return configuration;
    }
}

package com.cookie.config;

import com.cookie.pojo.Configuration;
import com.cookie.pojo.MapperStatement;
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;

public class XMLMapperBuilder {

    private Configuration configuration;


    public XMLMapperBuilder(Configuration configuration) {
        this.configuration = configuration;
    }

    public void parse(InputStream inputStream) throws DocumentException, ClassNotFoundException {
        Document document = new SAXReader().read(inputStream);
        Element rootElement = document.getRootElement();

        String namespace = rootElement.attributeValue("namespace");
        List<Element> select = rootElement.selectNodes("select");
        for (Element element : select) {
            String id = element.attributeValue("id");
            String paramType = element.attributeValue("paramType");
            String resultType = element.attributeValue("resultType");
            String sql = element.getTextTrim();
/*
            //输入参数class
            Class<?> paramterTypeClass = getClassType(paramterType);
            //返回结果class
            Class<?> resultTypeClass = getClassType(resultType);
*/

            //statementId
            String key = namespace + "." +id;
            //封装 mappedStatement
            MapperStatement mapperStatement = new MapperStatement();
            mapperStatement.setId(id);
            mapperStatement.setResultType(resultType);
            mapperStatement.setParamType(paramType);
            mapperStatement.setSql(sql);
            configuration.getMap().put(key, mapperStatement);

        }


    }


    private Class<?> getClassType(String paramterType) throws ClassNotFoundException {
        Class<?> aClass = Class.forName(paramterType);
        return aClass;
    }
}

package com.cookie.sqlSession;

public interface SqlSessionFactory {

    SqlSession openSession();

}

package com.cookie.sqlSession;

import com.cookie.pojo.Configuration;

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.cookie.sqlSession;

import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.List;

public interface SqlSession {


    //查询所有
    <E> List<E> selectList(String statementid,Object... params) throws SQLException, IllegalAccessException, IntrospectionException, InstantiationException, NoSuchFieldException, InvocationTargetException, ClassNotFoundException;

    //根据条件查询单个
    <T> T selectOne(String statementid,Object... params) throws IllegalAccessException, ClassNotFoundException, IntrospectionException, InstantiationException, SQLException, InvocationTargetException, NoSuchFieldException;


}

package com.cookie.sqlSession;

import com.cookie.pojo.Configuration;
import com.cookie.pojo.MapperStatement;

import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.List;

public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public <E> List<E> selectList(String statementid, Object... params) throws SQLException, IllegalAccessException, IntrospectionException, InstantiationException, NoSuchFieldException, InvocationTargetException, ClassNotFoundException {
        //完成simpleExecutor里的
        MapperStatement mapperStatement = configuration.getMap().get(statementid);
        SimpleExecutor simpleExecutor = new SimpleExecutor();
        List<Object> list = simpleExecutor.query(configuration, mapperStatement, params);
        return (List<E>) list;
    }

    @Override
    public <T> T selectOne(String statementid, Object... params) throws IllegalAccessException, ClassNotFoundException, IntrospectionException, InstantiationException, SQLException, InvocationTargetException, NoSuchFieldException {
        List<Object> objects = selectList(statementid, params);
        if (objects.size() == 1){
            return (T)objects.get(0);
        }else {
            throw new RuntimeException("查询结果为空或返回结果过多");
        }
    }
}

package com.cookie.sqlSession;

import com.cookie.pojo.Configuration;
import com.cookie.pojo.MapperStatement;

import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.List;

public interface Executor {


    <E> List<E> query(Configuration configuration, MapperStatement mapperStatement,Object... params) throws SQLException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException, IntrospectionException, InvocationTargetException, InstantiationException;
}

package com.cookie.sqlSession;

import com.cookie.config.BoundSql;
import com.cookie.pojo.Configuration;
import com.cookie.pojo.MapperStatement;
import com.cookie.utils.GenericTokenParser;
import com.cookie.utils.ParameterMapping;
import com.cookie.utils.ParameterMappingTokenHandler;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class SimpleExecutor implements Executor {
    @Override
    public <E> List<E> query(Configuration configuration, MapperStatement mapperStatement, Object... params) throws SQLException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException, IntrospectionException, InvocationTargetException, InstantiationException {
        //1.注册驱动,获取链接
        Connection connection = configuration.getDataSource().getConnection();

        //2.获取sql语句 :select * from user where id = #{id} and username = #{username}
        //转换sql语句   select * from where id = ? and username = ?
        //转换过程中对#{}里的值解析存储
        String sql = mapperStatement.getSql();
        BoundSql boundSql = getBoundSql(sql);

        //3.获取预处理对象:preparedStatement
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());

        //4.设置参数
        String paramType = mapperStatement.getParamType();
        Class<?> paramTypeClass = getClassType(paramType);

        List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
        for (int i = 0; i < parameterMappingList.size(); i++) {
            ParameterMapping parameterMapping = parameterMappingList.get(i);
            String content = parameterMapping.getContent();
            //反射
            Field declaredField = paramTypeClass.getDeclaredField(content);
            //暴力访问
            declaredField.setAccessible(true);
            Object o = declaredField.get(params[0]);
            preparedStatement.setObject(i+1,o);
        }
        //5.执行sql
        ResultSet resultSet = preparedStatement.executeQuery();
        //6.封装返回结果值
        String resultType = mapperStatement.getResultType();
        Class<?> resultTypeClass = getClassType(resultType);
        ArrayList<Object> objects = new ArrayList<>();
        while(resultSet.next()){
            Object o = resultTypeClass.newInstance();
            ResultSetMetaData metaData = resultSet.getMetaData();
            for (int i = 1;i <= metaData.getColumnCount(); i++){
                //字段名
                String columnName = metaData.getColumnName(i);
                //字段的值
                Object object = resultSet.getObject(columnName);
                //使用反射或者内省,根据数据库表和实体的对应关系完成封装
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeClass);
                Method writeMethod = propertyDescriptor.getWriteMethod();
                writeMethod.invoke(o,object);
            }
            objects.add(o);
        }
        return (List<E>) objects;
    }

    /**
     * 完成对#{}的解析 1.将#{}使用?进行代替 2.将#{}的值进行存储
     * @param sql
     * @return
     */
    private BoundSql getBoundSql(String sql) {
        //标记处理类:配合标记解析器来对标记占位符来进行处理工作
        ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
        GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", parameterMappingTokenHandler);
        //解析出来的sql
        String parse = genericTokenParser.parse(sql);
        //#{}里解析出来的参数名称
        List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();
        BoundSql boundSql = new BoundSql(parse,parameterMappings);
        return boundSql;
    }

    private Class<?> getClassType(String paramterType) throws ClassNotFoundException {
        Class<?> aClass = Class.forName(paramterType);
        return aClass;
    }
}

package com.cookie.config;

import com.cookie.utils.ParameterMapping;

import java.util.ArrayList;
import java.util.List;

public class BoundSql {


    private String sqlText;

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

5. 自定义框架优化

自定义框架解决了JDBC操作数据库带来的一些问题:例如频繁创建释放数据库连接,硬编码,手动封装返回结果集等问题。
自定义框架代码,仍有如下问题:

  1. dao的实现类中存在重复的代码,整个操作的过程模板重复(创建sqlsession,调用sqlsession方法,关闭sqlsession)
  2. dao的实现类中存在硬编码,调用sqlsession的方法时,参数statement的id硬编码

解决:使用代理模式来创建接口的代理对象(不用Dao接口实现类)

public interface SqlSession {


    //查询所有
    <E> List<E> selectList(String statementid,Object... params) throws SQLException, IllegalAccessException, IntrospectionException, InstantiationException, NoSuchFieldException, InvocationTargetException, ClassNotFoundException;

    //根据条件查询单个
    <T> T selectOne(String statementid,Object... params) throws IllegalAccessException, ClassNotFoundException, IntrospectionException, InstantiationException, SQLException, InvocationTargetException, NoSuchFieldException;

    //为Dao接口生成代理实现类
    <T> T getMapper(Class<?> mapperClass);

}
public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public <E> List<E> selectList(String statementid, Object... params) throws SQLException, IllegalAccessException, IntrospectionException, InstantiationException, NoSuchFieldException, InvocationTargetException, ClassNotFoundException {
        //完成simpleExecutor里的
        MapperStatement mapperStatement = configuration.getMap().get(statementid);
        SimpleExecutor simpleExecutor = new SimpleExecutor();
        List<Object> list = simpleExecutor.query(configuration, mapperStatement, params);
        return (List<E>) list;
    }

    @Override
    public <T> T selectOne(String statementid, Object... params) throws IllegalAccessException, ClassNotFoundException, IntrospectionException, InstantiationException, SQLException, InvocationTargetException, NoSuchFieldException {
        List<Object> objects = selectList(statementid, params);
        if (objects.size() == 1){
            return (T)objects.get(0);
        }else {
            throw new RuntimeException("查询结果为空或返回结果过多");
        }
    }

    @Override
    public <T> T getMapper(Class<?> mapperClass) {
        //使用JDK动态代理来为Dao接口生成代理对象,并返回
        Object o = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //底层还是执行JDBC代码 //根据不同情况,来调用selectList或者selectOne
                //准备参数 1:statementId : sql语句的唯一标识:namespace.id=接口全限定名.方法名
                //方法名:findAll
                String methedName = method.getName();
                String className = method.getDeclaringClass().getName();
                String statementId = className + "." + methedName;
                //准备参数2:params:args
                //获取被调用方法的返回值类型
                Type returnType = method.getGenericReturnType();
                //判断是否进行了泛型类型参数化
                if (returnType instanceof ParameterizedType){
                    List<Object> objects = selectList(statementId, args);
                    return objects;
                }
                return selectOne(statementId, args);
            }
        });
        return (T)o;
    }
}

public interface UserDao {

    //查询所有
    List<User> findAll() throws Exception;

    //根据条件查询单个
    User findByCondition(User user) throws Exception;


}
<mapper namespace="com.cookie.dao.UserDao">

    <!--sql的唯一标识:namespace.id组成 :statementId -->
    <select id="findAll" resultType="com.cookie.pojo.User">
        select * from user
    </select>

    <!--多个参数传递封装对象-->
    <select id="findByCondition" resultType="com.cookie.pojo.User" paramType="com.cookie.pojo.User">
        select * from user where id = #{id} and username = #{username}
    </select>



</mapper>
    @Test
    public void testMappeer() throws Exception {
        InputStream inputStream = Resources.getResourceAsSteam("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();


        User user = new User();
        user.setId(2);
        user.setUsername("tom");
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        List<User> all = userDao.findAll();
        all.forEach(System.out::println);

        User user1 = userDao.findByCondition(user);
        System.out.println(user1);

    }
  • 12
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值