马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
Mybatis解析
0.引入
Mybatis源码也是对Jbdc的再一次封装,不管怎么进行包装,还是会有获取链接、preparedStatement、封装参数、执行这些步调的。本文来探索一下其运行原理。下面从最简单的mybatis利用案例,来看看mybatis的步调。- public class Test01 {
- // 测试方法!============
- public static void main(String[] args) {
- String configFile = "mybatis-config.xml";
- try (
- // 1. 加载配置文件
- InputStream inputStream = Resources.getResourceAsStream(configFile)) {
- // 2. 创建 SqlSessionFactory 对象
- SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
- // 3. 获取 SqlSession 对象
- SqlSession sqlSession = sessionFactory.openSession();
- // 获取mapper
- InventoryMapper inventoryMapper = sqlSession.getMapper(InventoryMapper.class);
- // 调用mapper的方法
- List<Inventory> allInventory = inventoryMapper.getAllInventory();
- for (Inventory inventory : allInventory) {
- System.out.println(inventory);
- }
-
- // System.out.println(inventoryMapper.getInventoryById(1));
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- }
- // 实体类对象
- @AllArgsConstructor
- @NoArgsConstructor
- @Data
- public class Inventory implements Serializable {
- private static final long serialVersionUID = 1L;
- private Integer goodsId;
- private String goodsName;
- private Date createTime;
- private Date modifyTime;
- private Integer inventory;
- }
复制代码 数据库配置文件- db.driver=com.mysql.cj.jdbc.Driver
- db.url=jdbc:mysql://127.0.0.1:3306/trans_inventory?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
- db.username=root
- db.password=123456
复制代码 配置文件如下:- <?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>
- <properties resource="db.properties" />
- <settings>
-
- <setting name="mapUnderscoreToCamelCase" value="true"/>
- </settings>
-
- <environments default="development">
- <environment id="development">
-
- <transactionManager type="jdbc" />
-
- <dataSource type="pooled">
- <property name="driver" value="${db.driver}" />
- <property name="url" value="${db.url}" />
- <property name="username" value="${db.username}" />
- <property name="password" value="${db.password}" />
- </dataSource>
- </environment>
- </environments>
- <mappers>
- <mapper resource="mapper/InventoryMapper.xml" />
- </mappers>
- </configuration>
复制代码 mapper接口和xml文件- public interface InventoryMapper {
- List<Inventory> getAllInventory();
- Inventory getInventoryById(@Param("id") Integer id);
- }
复制代码- <?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.feng.mapper.InventoryMapper">
- <select id="getAllInventory" resultType="com.feng.entity.Inventory">
- select *
- from inventory
- </select>
-
- <select id="getInventoryById" resultType="com.feng.entity.Inventory">
- select *
- from inventory
- where goods_id = #{id}
- </select>
- </mapper>
复制代码 1.加载配置文件
InputStream inputStream = Resources.getResourceAsStream(configFile)
可以看到是这一行代码。其中Resources是Mybatis的工具类。从这个开始一层一层往下看- public class Resources {
- // new 了一个ClassLoaderWrapper对象
- private static final ClassLoaderWrapper classLoaderWrapper = new ClassLoaderWrapper();
-
- public static InputStream getResourceAsStream(String resource) throws IOException {
- return getResourceAsStream(null, resource);
- }
-
- // loader = null, resource = "xxxx.xml"
- public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException {
- // ====================== 这一行
- InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader);
- if (in == null) {
- throw new IOException("Could not find resource " + resource);
- }
- return in;
- }
- }
- public class ClassLoaderWrapper {
- ClassLoader defaultClassLoader;
- ClassLoader systemClassLoader;
- // --------- 构造函数
- ClassLoaderWrapper() {
- try {
- // jdk的方法,得到系统类加载器
- systemClassLoader = ClassLoader.getSystemClassLoader();
- } catch (SecurityException ignored) {
- // AccessControlException on Google App Engine
- }
- }
-
- public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {
- // getResourceAsStream()方法里面用到了 getClassLoaders(null)
- return getResourceAsStream(resource, getClassLoaders(classLoader));
- }
- // 得到所有的类加载器:::classLoader = null
- ClassLoader[] getClassLoaders(ClassLoader classLoader) {
- return new ClassLoader[] { classLoader, defaultClassLoader, Thread.currentThread().getContextClassLoader(),
- getClass().getClassLoader(), systemClassLoader };
- }
- // 遍历所有的类加载器,谁加载到了就返回谁的inputStream
- InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
- for (ClassLoader cl : classLoader) {
- if (null != cl) {
- // try to find the resource as passed
- InputStream returnValue = cl.getResourceAsStream(resource);
- // now, some class loaders want this leading "/", so we'll add it and try again if we didn't find the resource
- if (null == returnValue) {
- returnValue = cl.getResourceAsStream("/" + resource);
- }
- if (null != returnValue) {
- return returnValue;
- }
- }
- }
- return null;
- }
- }
复制代码 主要是通过ClassLoader.getResourceAsStream()方法获取指定的classpath路径下的Resource
2.创建SqlSessionFactory
- // 2. 创建 SqlSessionFactory 对象
- SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
复制代码 第一步,无参构造函数创建了一个SqlSessionFactoryBuilder对象,然后调用其build方法。这很明显是“建造者设计模式”。
主要来看后面的build(inputStream)方法
[code]public class SqlSessionFactoryBuilder { public SqlSessionFactory build(InputStream inputStream) { return build(inputStream, null, null); } public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { try { //1.创建一个xml解析的builder,是建造者模式 XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); // 2.上面创建的parser.parse()【可以理解为创建Configuration对象,并设置其属性】 return build(parser.parse()); // 3.build出SqlSessionFactory } catch (Exception e) { throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { if (inputStream != null) { inputStream.close(); } } catch (IOException e) { // Intentionally ignore. Prefer previous error. } } } // 3.我们发现SqlSessionFactory默认是DefaultSqlSessionFactory类型的 public SqlSessionFactory build(Configuration config) { return new DefaultSqlSessionFactory(config); }}// XMLConfigBuilder.java内里public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) { this(Configuration.class, inputStream, environment, props); }public XMLConfigBuilder(Class |