我们在实际开发中,越简单越好,所以都是采用不写Dao实现类的方式。不管是使用xml还是直接配置。
但是MyBatis是支持写Dao实现类的
注意sqlSession是这里面的一个灵魂,有很多执行api
目录结构:
方法:
/** * 用户的持久层接口 */ public interface IUserDao { ListfindAll(); }
实现类:
public class UserDaoImpl implements IUserDao { private SqlSessionFactory factory; //覆盖掉默认构造函数,这样就有了工厂,可以进一步创建对象 public UserDaoImpl(SqlSessionFactory factory){ this.factory = factory; } @Override public ListfindAll() { //1.使用工厂创建SqlSession对象 SqlSession sqlSession = factory.openSession(); //2.使用sqlSession执行查询所有方法(此处需要的参数:(String statement)从配置文件中获取) namespace + id List 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"> <environment id="mysql"> <transactionManager type="JDBC">transactionManager> <dataSource type="POOLED"> <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> <mappers> <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.使用代理对象执行方法 ListuserList = 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
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接口的字节码创建到的代理对象
publicgetMapper(Class 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.0modelVersion> <groupId>com.testgroupId> <artifactId>mybatisartifactId> <version>1.0-SNAPSHOTversion> <dependencies> <dependency> <groupId>mysqlgroupId> <artifactId>mysql-connector-javaartifactId> <version>5.1.6version> dependency> <dependency> <groupId>log4jgroupId> <artifactId>log4jartifactId> <version>1.2.12version> dependency> <dependency> <groupId>junitgroupId> <artifactId>junitartifactId> <version>4.10version> dependency> dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.pluginsgroupId> <artifactId>maven-compiler-pluginartifactId> <version>3.6.1version> <configuration> <source>1.8source> <target>1.8target> configuration> plugin> plugins> build> project>
构建者构建工厂,工厂生产SqlSession。SqlSession可以做的事情很多。
总结:读取配置文件io流,解析出我们要的信息,交给构建者,构建者使用工具类,构建了工厂对象,工厂的openSession方法提供了sqlSession对象,sqlSession去干活。