MyBatis原理总结(手写实现类)
Posted toov5
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis原理总结(手写实现类)相关的知识,希望对你有一定的参考价值。
我们在实际开发中,越简单越好,所以都是采用不写Dao实现类的方式。不管是使用xml还是直接配置。
但是MyBatis是支持写Dao实现类的
注意sqlSession是这里面的一个灵魂,有很多执行api
目录结构:
方法:
/** * 用户的持久层接口 */ public interface IUserDao List<User> findAll();
实现类:
public class UserDaoImpl implements IUserDao private SqlSessionFactory factory; //覆盖掉默认构造函数,这样就有了工厂,可以进一步创建对象 public UserDaoImpl(SqlSessionFactory factory) this.factory = factory; @Override public List<User> findAll() //1.使用工厂创建SqlSession对象 SqlSession sqlSession = factory.openSession(); //2.使用sqlSession执行查询所有方法(此处需要的参数:(String statement)从配置文件中获取) namespace + id List<User> userList = sqlSession.selectList("com.toov5.dao.IUserDao.findAll"); //使用完后关闭掉 sqlSession.close(); return userList;
实体类:
public class User implements Serializable private Integer id; private String username; private Date birthday; private String sex; private String address; 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; public Date getBirthday() return birthday; public void setBirthday(Date birthday) this.birthday = birthday; public String getSex() return sex; public void setSex(String sex) this.sex = sex; public String getAddress() return address; public void setAddress(String address) this.address = address; @Override public String toString() return "User" + "id=" + id + ", username=‘" + username + ‘\\‘‘ + ", birthday=" + birthday + ", sex=‘" + sex + ‘\\‘‘ + ", address=‘" + address + ‘\\‘‘ + ‘‘;
全局配置文件:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 配置环境 --> <environments default="mysql"> <!-- 配置mysql的环境--> <environment id="mysql"> <!-- 配置事务的类型--> <transactionManager type="JDBC"></transactionManager> <!-- 配置数据源(也叫连接池) --> <dataSource type="POOLED"> <!-- 配置连接数据库的4个基本信息 --> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/test"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件 --> <mappers> <!--resource目录下 对应要创建相应的包 --> <mapper resource="com/toov5/dao/IUserDao.xml"/> </mappers> </configuration>
映射文件:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.toov5.dao.IUserDao"> <!--查询所有--> <select id="findAll" resultType="com.toov5.entity.User"> select * from user; </select> </mapper>
测试类:
/** * MyBatis测试类 */ public class MyBatisTest public static void main(String[] args) throws IOException //1.读取配置文件 InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml"); //2. 创建SqlSessonFactory工厂 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //如何解析,如何封装已经底层帮助实现了。细节封装了。 SqlSessionFactory factory = builder.build(in); // SqlSessionFactory 是个接口,需要找实现。这个工厂是用来创建对象的,创建过程省略了 //3. 使用工厂生产SqlSession对象 SqlSession sqlSession = factory.openSession(); //不需要代理类了,SqlSession 是有查询方法的.使用工厂创建Dao对象,传入工厂 IUserDao userDao = new UserDaoImpl(factory); //5.使用代理对象执行方法 List<User> userList = userDao.findAll(); userList.stream().forEach( user -> System.out.println(user); ); //6.释放资源 in.close();
Mybatis在用动态代理dao方式时候,也是找到对应的sql语句的。
执行结果,一模一样。
引申
补充,对于绝对路径和相对路径,绝对路径不准确,采用相对路径。
相对路径有两种方案可以获得。 1. 类加载器,只能读取类路径的配置文件 2. 使用ServletContext对象的getRealPath()
创建工厂,采用了构建这模式。隐藏了创建细节。使用户直接调用方法就可以拿到对象了
使用工厂模式生产SqlSession。降低类间的依赖,解耦合。
创建dao接口实现类使用了代理模式。不修改源码基础上对已有的方法增强。
MyBatis原理分析:
MyBatis在使用代理Dao的方式实现增删改查时候,做的什么事呢?
两件事:
一: 创建对象
二: 在代理对象中调用selectList
从一开始就需要解析配置文件,
进而做如下操作:
1. 根据配置文件的信息创建Connection对象,注册驱动,获取连接
2. 获取愈合粗粒对象PreparedStatement,此时需要SQL语句。 com.prepareStatement(sql)
3. 执行查询 ResultSet resultSet = preparedStatement.executeQuery();
4.遍历结果用于封装
List<E> list = new ArrayList();
while(resultSet.next())
E element = xxx; // 可以通过反射后去 class.forName("配置的全限定类名").newInstance(); 使用反射封装
// 进行封装。把每个rs的内容都添加到element中,把element加入到list中
list.add(element);
于是我们就可以把表的列名看成是实体类的属性名称,就可以使用反射的方式来根据名称获取每个属性。
5.返回结果
综上所述: 需要提供方法两个信息
1. 连接信息
2. 映射信息,包含两部分: 执行的sql语句; 封装结果的实体类全限定类名。这两个信息作为属性定义对象。
String key : nameSpace+id
Mapper value : String的sql语句 方法的全类名
通过方法:
session.getMapper(IUserDao.class) 实现了代理对象的创建
根据dao接口的字节码创建到的代理对象
public <T> getMapper(Class<T> daoInterfaceClass)
使用的的参数是 : 类加载器(与被代理对象使用相同的类加载器), Class数组:代理对象要实现接口的字节码数组, 如何代理(Handler)
Proxy.newProxyInstance()
此方法的封装:
s1.类加载器: 它使用的和被代理对象是相同的类加载器
s2.代理对象要实现的接口: 和被代理对象实现相同的接口
s3.如何代理: 它就是增强的方法,我们需要自己来提供
此处是一个InvocationHandler的接口,我们需要写一个该接口的实现类
调用该类的selectList方法
自定义MyBatis能通过入门案例看到的类:
class Resources
class SqlSessionFactoryBuilder
interface SqlSessionFactory
此时的pom:
<?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"> <modelVersion>4.0.0</modelVersion> <groupId>com.test</groupId> <artifactId>mybatis</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!--<dependency>--> <!--<groupId>org.mybatis</groupId>--> <!--<artifactId>mybatis</artifactId>--> <!--<version>3.4.5</version>--> <!--</dependency>--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</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> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.6.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
构建者构建工厂,工厂生产SqlSession。SqlSession可以做的事情很多。
总结:读取配置文件io流,解析出我们要的信息,交给构建者,构建者使用工具类,构建了工厂对象,工厂的openSession方法提供了sqlSession对象,sqlSession去干活。
以上是关于MyBatis原理总结(手写实现类)的主要内容,如果未能解决你的问题,请参考以下文章