自定义持久层框架的实现

1.自定义持久层框架

1.1 分析JDBC操作问题

# 1.引入相关依赖
- mysql-connector-java
- druid
# 2.编写工具类
# 3.编写测试类

传统方式

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

public class JdbcUtils {
    private static Properties properties;
    private static String url;
    private static String username;
    private static String password;
    private static String driver;
    private static Boolean flag = true;

    static{
        if(flag){
            properties = new Properties();
            try {
                properties.load(JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties"));
                url = properties.getProperty("url");
                username = properties.getProperty("username");
                password = properties.getProperty("password");
                driver = properties.getProperty("driver");
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                properties.clear();
            }
            flag = false;
        }
    }

    //每一次的连接对象都是不同的
    public static Connection getConnection() throws ClassNotFoundException, SQLException {
        //1.注册驱动
        Class.forName(driver);
        //2.获得连接对象
        return DriverManager.getConnection(url, username, password);
    }
}

连接池方式

import com.alibaba.druid.pool.DruidDataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

public class DruidUtils {
    private static DruidDataSource dataSource;
    private static Properties properties;
    private static Boolean flag = true;

    static {
        if(flag){
            properties = new Properties();
            try {
                properties.load(JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties"));
                dataSource = new DruidDataSource();
                dataSource.setDriverClassName(properties.getProperty("driver"));
                dataSource.setUrl(properties.getProperty("url"));
                dataSource.setUsername(properties.getProperty("username"));
                dataSource.setPassword(properties.getProperty("password"));

                dataSource.setMaxActive(3);//连接池的最大数量
            }catch (IOException e){
                e.printStackTrace();
            }finally {
                properties.clear();
            }
            flag = false;
        }
    }

    //每一次的连接对象都是不同的,但是当连接关闭后会返回到池子中
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }
}

测试类

        Connection conn = null;
        try {
            //1.获取连接
            conn = JdbcUtils.getConnection();
            //2.编写SQL语句
            String sql = "select * from user where name = ?;";
            //3.获取执行SQL的对象
            PreparedStatement statement = conn.prepareStatement(sql);
            //4.填充
            statement.setString(1,"灰二");
            //5.执行
            ResultSet resultSet = statement.executeQuery();
            //6.遍历
            while (resultSet.next()){
                System.out.print(resultSet.getInt(1)+"+");
                System.out.print(resultSet.getString(2)+"+");
                System.out.println(resultSet.getInt(3));
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            if(conn == null){
                try {
                    conn.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
        }

JDBC问题总结

# 原始JDBC开发存在的问题
- 1.数据库配置信息存在硬编码问题,频繁创建释放数据库连接。
- 2.sql语句、设置参数、获取结果集均存在硬编码问题。
- 3.手动封装返回结果集,步骤繁琐。

1.2 问题解决思路

# 1.配置文件 2.连接池 3.反射、内省

1.3 自定义框架设计

使用端

# 提供核心配置文件
- sqlMapConfig.xml:存放数据库配置信息,存放mapper.xml的全路径
- mapper.xml:存放sql配置信息

框架段

# 加载配置文件:根据配置文件的路径,加载配置文件成输入字节流,存储在内存中
- 创建Resources类 方法:InputStream getResourceAsStream(String path);

# 创建两个JavaBean:存放对配置文件解析出来的内容
- Configuration:核心配置类,存放sqlMapConfig.xml解析出来的内容
- MappedStatement:映射配置类,存放mapper.xml解析出来的内容

# 解析配置文件:dom4j
- 创建类:SqlSessionFactoryBuild 方法:build(InpuStream in)
- 使用dom4j解析配置文件,将解析出来的内容封装到JavaBean中
- 创建SqlSessionFactory对象:生产SqlSession对象[会话对象]

# 创建SqlSessionFactory接口和实现类DefaultSqlSessionFactory
- 方法:openSession(),生产SqlSession

# 创建SqlSession接口和实现类DefaultSession
- 定义对象数据库的crud操作
	- selectList
	- selectOne
    
# 创建Executor接口和实现类SimpleExecutor
- 方法:query(Configuration,MappedStatement,Object...params)。对JDBC方法的封装

涉及到的设计模式

Builder构建者设计模式、工厂模式、代理模式

1.4 自定义框架实现

使用端

1.数据源的配置文件

2.sql语句的配置文件

3.POJO类

4.导入框架端的依赖

sqlMapConfig

<configuration>
    <dataSource>
        <property name="driverName" value="com.mysql.cj.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/huier_zdy_mybatis?serverTimezone=Asia/Shanghai"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </dataSource>

    <mapper resource="userMapper.xml"></mapper>
</configuration>

mapper.xml

<mapper namespace="user">

    <!--唯一标识:namespace.id-->

    <select id="selectList" resultType="com.huier.pojo.User">
        select * from user;
    </select>

<!--    <select id="selectOne">-->
<!--        select * from user where id = ?;-->
<!--    </select>-->

    <select id="selectOne" paramterType="com.huier.pojo.User" resultType="com.huier.pojo.User">
        select * from user where id = #{id} and username = #{username};
    </select>
</mapper>

实体类

public class User {
    private Long id;
    private String username;

    public Long getId() {
        return id;
    }

    public void setId(Long 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 + '\'' +
                '}';
    }
}

在这里插入图片描述

框架端

1.将配置文件以流的形式存在内存中

2.将配置文件的信息封装到JavaBean中,生成工厂

3.通过工厂生成会话对象

jar包依赖

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.22</version>
        </dependency>

        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.1</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.14</version>
        </dependency>
    </dependencies>

Resources

public class Resources {

    //作用:将文件加载到内存中以流的形式存在
    public static InputStream getResourceAsStream(String path){
        return Resources.class.getClassLoader().getResourceAsStream(path);
    }
}

SqlSessionFactoryBuild

public class SqlSessionFactoryBuild {

    //加载配置文件到JavaBean中,生成工厂
    public SqlSessionFactory build(InputStream in) throws DocumentException {
        //1.使用dom4j解析xml,封装javaBean
        XMLConfigBuildr xmlConfigBuildr = new XMLConfigBuildr();
        Configuration configuration = xmlConfigBuildr.parseConfig(in);
        //2.创建SqlSessionFactory对象
        return new DefaultSqlSessionFactory(configuration);
    }
}

JavaBean

Configuration

public class Configuration {
    //1.数据源
    private DataSource dataSource;

    //2.唯一映射
    private Map<String,MappedStatement> mappedStatementMap = new HashMap<String, MappedStatement>();

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

MappedStatement

//封装sql配置信息
public class MappedStatement {
    private String id;//标识
    private String resultType;
    private String paramterType;
    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 getParamterType() {
        return paramterType;
    }

    public void setParamterType(String paramterType) {
        this.paramterType = paramterType;
    }

    public String getSql() {
        return sql;
    }

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

XML解析,封装JavaBean

XMLConfigBuilder

//解析Configuration.xml
public class XMLConfigBuildr {

    private Configuration configuration;

    public XMLConfigBuildr(){
        this.configuration = new Configuration();
    }

    public Configuration parseConfig(InputStream in) throws DocumentException {
        Document document = new SAXReader().read(in);
        Element root = document.getRootElement();
        List<Element> list = root.selectNodes("//property");
        Properties properties = new Properties();
        for (Element element : list) {
           String name = element.attributeValue("name");
           String value = element.attributeValue("value");
           properties.put(name,value);
        }
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(properties.getProperty("driverName"));
        druidDataSource.setUrl(properties.getProperty("url"));
        druidDataSource.setUsername(properties.getProperty("username"));
        druidDataSource.setPassword(properties.getProperty("password"));
        configuration.setDataSource(druidDataSource);
        List<Element> mappers = root.selectNodes("//mapper");
        for (Element mapper : mappers) {
            String mapperPath = mapper.attributeValue("resource");
            InputStream stream = Resources.getResourceAsStream(mapperPath);
            XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(configuration);
            xmlMapperBuilder.parse(stream);
        }
        return configuration;
    }
}

XMLMapperBuilder

public class XMLMapperBuilder {

    private Configuration configuration;

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

    public void parse(InputStream in) throws DocumentException {
        Document document = new SAXReader().read(in);
        Element root = document.getRootElement();
        List<Element> list = root.selectNodes("//select");
        String namespace = root.attributeValue("namespace");
        Map<String,MappedStatement> mappedStatementMap = new HashMap<String, MappedStatement>();
        for (Element element : list) {
            String paramterType = element.attributeValue("paramterType");
            String resultType = element.attributeValue("resultType");
            String id = element.attributeValue("id");
            String sql = element.getTextTrim();
            MappedStatement mappedStatement = new MappedStatement();
            mappedStatement.setId(id);
            mappedStatement.setParamterType(paramterType);
            mappedStatement.setResultType(resultType);
            mappedStatement.setSql(sql);
            mappedStatementMap.put(namespace+"."+id,mappedStatement);
        }
        configuration.setMappedStatementMap(mappedStatementMap);
    }
}

SqlSessionFactory接口

//用来生产SqlSession对象
public interface SqlSessionFactory {
    public SqlSession openSession();
}

DefaultSqlSessionFactory

public class DefaultSqlSessionFactory implements SqlSessionFactory {
    private Configuration configuration;

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

    public SqlSession openSession() {
        return new DefaultSqlSession(configuration);
    }
}

SqlSession接口

public interface SqlSession {
    //可能模糊查询
    public <E> List<E> selectList(String statementId,Object... params) throws Exception;

    public <E>  E selectOne(String statementId,Object... params) throws Exception;
}

DefaultSqlSession

public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

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

    public <E> List<E> selectList(String statementId, Object... params) throws Exception {
        Executor executor = new DefaultExecutor();
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
        return executor.query(configuration,mappedStatement,params);
    }

    public <E> E selectOne(String statementId, Object... params) throws Exception {
        List<Object> list = selectList(statementId, params);

        if(list.size() == 1){
            return (E) list.get(0);
        }else{
            throw new RuntimeException("结果过多");
        }
    }
}

Executor:封装底层具体的jdbc代码

Executor接口

public interface Executor {

    public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement,Object... params) throws SQLException, Exception;
}

DefaultExecutor

public class DefaultExecutor implements Executor {
    public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception {
        Connection connection = configuration.getDataSource().getConnection();
        //select * from user where id = #{id} and username = #{username}
        String sql = mappedStatement.getSql();
        BoundSql boundSql = getBoundSql(sql);//将原始sql转换成可预编译的sql语句
        PreparedStatement statement = connection.prepareStatement(boundSql.getSqlTest());
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();//参数
        Class clz = getParamterClass(mappedStatement.getParamterType());//获得参数类
        for (int i = 0; i < parameterMappings.size(); i++) {
            ParameterMapping parameterMapping = parameterMappings.get(i);
            String canshu = parameterMapping.getContent();//#{id} 值
            Field declaredField = clz.getDeclaredField(canshu);
            declaredField.setAccessible(true);
            Object o = declaredField.get(params[0]);
            statement.setObject(i+1,o);
        }
        ResultSet resultSet = statement.executeQuery();
        List<E> result = new ArrayList<E>();
        Class resultClz = getParamterClass(mappedStatement.getResultType());
        while (resultSet.next()){
            ResultSetMetaData metaData = resultSet.getMetaData();//每一行的数据
            Object o = resultClz.newInstance();//创建实体对象
            for(int i = 1;i <= metaData.getColumnCount();i++){
                String filedName = metaData.getColumnName(i);
                Object filedValue = resultSet.getObject(filedName);
                //反射
                Field declaredField = resultClz.getDeclaredField(filedName);
                declaredField.setAccessible(true);
                declaredField.set(o,filedValue);//设置值

//                //内省
//                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(filedName,resultClz);
//                Method writeMethod = propertyDescriptor.getWriteMethod();
//                writeMethod.invoke(o,filedValue);
            }
            result.add((E) o);
        }
        return result;
    }

    private Class getParamterClass(String paramterType) throws ClassNotFoundException {
        if(paramterType == null || "".equals(paramterType))return null;
        return Class.forName(paramterType);
    }

    private BoundSql getBoundSql(String sql) {
        //标记处理类:配置标记解析器来完成对占位符的解析处理工作
        ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler();

        GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
        String parseSql = parser.parse(sql);
        //#{}中的参数名称
        List<ParameterMapping> parameterMappings = handler.getParameterMappings();

        return new BoundSql(parseSql,parameterMappings);
    }
}

BoundSql:解析后的sql语句**{#{id} -> ?}**

public class BoundSql {
    private String sqlTest;

    private List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>();


    public BoundSql(String sqlTest, List<ParameterMapping> parameterMappings) {
        this.sqlTest = sqlTest;
        this.parameterMappings = parameterMappings;
    }

    public String getSqlTest() {
        return sqlTest;
    }

    public void setSqlTest(String sqlTest) {
        this.sqlTest = sqlTest;
    }

    public List<ParameterMapping> getParameterMappings() {
        return parameterMappings;
    }

    public void setParameterMappings(List<ParameterMapping> parameterMappings) {
        this.parameterMappings = parameterMappings;
    }
}

工具:将原始的sql语句转变成可以预编译处理的sql

GenericTokenParser

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

ParameterMapping

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

ParameterMappingTokenHandler

public class ParameterMappingTokenHandler implements TokenHandler {
	private List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>();

	// context是参数名称 #{id} #{username}

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

}

TokenHandler

public interface TokenHandler {
  String handleToken(String content);
}

在这里插入图片描述

测试
    @Test
    public void t() throws Exception {
        InputStream in = Resources.getResourceAsStream("sqlMapConfig.xml");//加载配置文件
        SqlSessionFactory factory = new SqlSessionFactoryBuild().build(in);//填充JavaBean,生成工厂
        SqlSession sqlSession = factory.openSession();//工厂生产SqlSession

        //测试selectOne
        User user = new User();
        user.setId(1L);
        user.setUsername("灰二");
        User user1 = sqlSession.selectOne("user.selectOne", user);
        System.out.println(user1);

        //测试selectList
        List<Object> objects = sqlSession.selectList("user.selectList");
       objects.forEach(System.out::println);
    }

在这里插入图片描述

1.5 自定义框架的优化

# 原始自定义框架存在的问题
-- 1.代码重复度高
	-- 加载配置文件
	-- 创建工厂
	-- 生成SqlSession
-- 2.存在硬编码问题
	-- sql的唯一标识需要手动书写
	
 # 解决
 -- 1.不要具体的实现类,使用代理模式生成Dao层接口的代理实现类
使用端

1.增加dao层接口,里面定义方法

2.修改mapper.xml配置文件内容

​ namspace:使用接口的全类名

​ id:使用接口中的方法名

UserMapper

public interface UserMapper {

    List<User> selectList();

    User selectOne(User user);
}

mapper.xml

<mapper namespace="com.huier.mapper.UserMapper">

    <!--唯一标识:namespace.id-->

    <select id="selectList" resultType="com.huier.pojo.User">
        select * from user;
    </select>

<!--    <select id="selectOne">-->
<!--        select * from user where id = ?;-->
<!--    </select>-->

    <select id="selectOne" paramterType="com.huier.pojo.User" resultType="com.huier.pojo.User">
        select * from user where id = #{id} and username = #{username};
    </select>
</mapper>
框架端

1.在SqlSession中增添获得代理对象的方法

2.通过被代理的对象的全类名+方法名获sql语句的唯一标识

SqlSession接口

public interface SqlSession {
    //可能模糊查询
    public <E> List<E> selectList(String statementId,Object... params) throws Exception;

    public <E>  E selectOne(String statementId,Object... params) throws Exception;

    //生成代理对象
    public <E> E getMapper(Class<?> mapperClass);
}

DefaultSqlSession

public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

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

    public <E> List<E> selectList(String statementId, Object... params) throws Exception {
        Executor executor = new DefaultExecutor();
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
        return executor.query(configuration,mappedStatement,params);
    }

    public <E> E selectOne(String statementId, Object... params) throws Exception {
        List<Object> list = selectList(statementId, params);

        if(list.size() == 1){
            return (E) list.get(0);
        }else{
            throw new RuntimeException("结果过多");
        }
    }

    public <E> E getMapper(Class<?> mapperClass) {
        //使用jdk动态代理
        /*
        三个参数
            1.类加载器
            2.class数组
            3.必须要实现的接口
         */
        Object proxyInstance = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
            /*
            proxy:当前代理对象的引用
            method:当前被调用方法的引用
            args:传递的参数
             */
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //底层还是执行jdbc代码
                //准备参数 1.namespace.id sql语句的唯一标识
                //接口全限定名+方法名
                String methodName = method.getName();//方法名
                String interfaceName = method.getDeclaringClass().getName();//接口全限定名
                String statementId = interfaceName+"."+methodName;
                //准备参数 2.参数
                Type genericReturnType = method.getGenericReturnType();//获得方法返回值类型
                if(genericReturnType instanceof ParameterizedType){//判断是否有泛型
                    return selectList(statementId,args);
                }else{
                    return selectOne(statementId,args);
                }
            }
        });
        return (E) proxyInstance;
    }
}
测试
    @Test
    public void t2() throws Exception {
        InputStream in = Resources.getResourceAsStream("sqlMapConfig.xml");//加载配置文件
        SqlSessionFactory factory = new SqlSessionFactoryBuild().build(in);//填充JavaBean,生成工厂
        SqlSession sqlSession = factory.openSession();//工厂生产SqlSession

        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = userMapper.selectList();
        users.forEach(System.out::println);
    }

    @Test
    public void t3() throws Exception {
        InputStream in = Resources.getResourceAsStream("sqlMapConfig.xml");//加载配置文件
        SqlSessionFactory factory = new SqlSessionFactoryBuild().build(in);//填充JavaBean,生成工厂
        SqlSession sqlSession = factory.openSession();//工厂生产SqlSession

        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User findUser = new User();
        findUser.setId(1L);
        findUser.setUsername("灰二");

        System.out.println(userMapper.selectOne(findUser));
    }
# 总结
# 1.使用端创建配置文件,框架端加载并存储配置信息,配置信息包含了数据源+sql信息。
# 2.sql配置文件的namespace.id是sql的唯一标识。
# 3.不使用动态代理:手动写namespace.id找到唯一sql语句然后执行。
# 4.使用动态代理:namespace必须是接口的全类名,id必须是方法名,通过被代理对象的方法获得信息,然后执行sql。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值