Mybatis


最开始,java通过JDBC访问数据库,JDBC的缺点

  1. jdbc没有使用连接池,操作数据库需要频繁的创建、关闭连接,浪费数据库资源;
  2. sql语句写在java代码中,如果sql语句修改,java代码需要重新编译,不利于系统维护;
  3. 通过prepareStatement向占位符设置参数,存在硬编码问题,占位符和参数需要一一对应;
  4. 解析结果集时,存在硬编码,且需要对结果集进行遍历。

现在可以用Mybatis替换JDBC连接数据库。

MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录,用于实现面向对象编程语言里不同类型系统间的数据转换
两种方式的优缺点:
注解不适合比较复杂的sql语句,如关联查询等;而且没有对sql语句进行统一的管理;修改需要重新编译;
xml方式增加了xml文件;对条件不确定的查询语句需要if判断;有特殊的转义字符,如小于;

一、代码

1.1 启动方法

public class MybatisTest {
   
  public static void main(String[] args) {
   
    String resources = "MybatisConfig.xml";
    try {
   
      Reader resourceAsReader = Resources.getResourceAsReader(resources);
      SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsReader);
      SqlSession sqlSession = sqlSessionFactory.openSession();
      sqlSession.selectOne("org.apache.ibatis.UserDao.getUser");
      // 另一种方法
      UserDao userDao = sqlSession.getMapper(UserDao.class);
      User user = userDao.selectUser("1");
    } catch (IOException e) {
   
      e.printStackTrace();
    }
  }
}

如果要使用sqlSession.getMapper(UserDao.class)的方法执行sql语句,必须要在配置文件里用package和class的方式加载映射文件。

1.2 配置文件MybatisConfig.xml

<configuration>
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC"/>
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver"/>
				<property name="url" value="jdbc:mysql://10.2.73.183:3306/user_server"/>
				<property name="username" value="root"/>
				<property name="password" value="password"/>
			</dataSource>
		</environment>
	</environments>
	<mappers>
		<mapper resource="user/UserMapper.xml"/>
	</mappers>
</configuration>
1.2.1 配置文件的结构

在这里插入图片描述
类型别名typeAliases:为 Java 类型设置一个短的名字,存在的意义仅在于用来减少类完全限定名的冗余。
类型处理器typeHandlers:无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型
映射器mappers:定义映射文件所在的位置。有xml和注解两种方式实现映射器,

1.3 UserMapper.xml

<?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="org.apache.ibatis.UserDao">
	<select id="getUser" resultType="org.apache.ibatis.User">
		select id, username, password from sys_user
	</select>
</mapper>

1.4 UserDao

public interface UserDao {
   
  User getUser();
}

二、本质

Mybatis连接数据库必备的几个组件:
在这里插入图片描述

  • DML:insert、delete、update语句
  • DQL:查询语句
  • DDL:建表语句

2.1 Mybatis如何获取数据源

在这里插入图片描述
用户调用new SqlSessionFactoryBuilder().build(stream);,build()方法中调用XMLConfigBuilder.parse()解析mybatis的配置文件中<configuration>标签下的配置,build()、parse()方法如下:

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
   
  try {
   
    XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
    return build(parser.parse());
  } catch (Exception e) {
   
    throw ExceptionFactory.wrapException("Error building SqlSession.", e);
  } finally {
   
    ErrorContext.instance().reset();
    try {
   
      inputStream.close();
    } catch (IOException e) {
   
      // Intentionally ignore. Prefer previous error.
    }
  }
}
  
public Configuration parse() {
   
  if (parsed) {
   
    throw new BuilderException("Each XMLConfigBuilder can only be used once.");
  }
  parsed = true;
  parseConfiguration(parser.evalNode("/configuration"));
  return configuration;
}

parseConfiguration()方法如下,root中存的就是MybatisConfig.xml中<configuration>标签下的内容。

  • **environmentsElement()**用来解析关于数据源的配置;
  • propertiesElement(root.evalNode(“properties”));:解析的是mybatis配置文件中在properties标签下定义的变量,因为最先解析的是properties,所以在配置文件中properties标签要在最上面;
private void parseConfiguration(XNode root) {
   
    try {
   
      //issue #117 read properties first
      propertiesElement(root.evalNode("properties"));
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      loadCustomLogImpl(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
   
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

propertiesElement()方法如下,首先获取配置文件中properties标签下的配置,再去获取指定路径文件中的配置,如果有相同的name,文件中的会覆盖标签中的,最后将配置放入configuration和parser的variables属性中
,优先级:url指定文件中的配置>resources指定文件中的配置>property标签中的配置。

private void propertiesElement(XNode context) throws Exception {
   
  if (context != null) {
   
    Properties defaults = context.getChildrenAsProperties();
    String resource = context.getStringAttribute("resource");
    String url = context.getStringAttribute("url");
    if (resource != null && url != null) {
   
      throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference.  Please specify one or the other.");
    }
    if (resource != null) {
   
      defaults.putAll(Resources.getResourceAsProperties(resource));
    } else if (url != null) {
   
      defaults.putAll(Resources.getUrlAsProperties(url));
    }
    Properties vars = configuration.getVariables();
    if (vars != null) {
   
      defaults.putAll(vars);
    }
    parser.setVariables(defaults);
    configuration.setVariables(defaults);
  }
}

environmentsElement()方法如下:

private void environmentsElement(XNode context) throws Exception {
   
    if (context != null) {
   
      if (environment == null) {
   
        environment = context.getStringAttribute("default");
      }
      for (XNode child : context.getChildren()) {
   
        String id = child.getStringAttribute("id");
        if (isSpecifiedEnvironment(id)) {
   
          TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
          DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
          DataSource dataSource = dsFactory.getDataSource();
          Environment.Builder environmentBuilder = new Environment.Builder(id)
              .transactionFactory(txFactory)
              .dataSource(dataSource);
          configuration.setEnvironment(environmentBuilder.build());
        }
      }
    }
  }

mybatis内置提供JDBC和MANAGED两种事务管理方式,前者主要用于简单JDBC模式,后者主要用于容器管理事务,一般使用JDBC事务管理方式。
dataSourceElement()方法用于解析dataSource标签下的内容,得到数据源工厂,通过DataSourceFactory.getDataSource()获取到数据源对象后,通过构建者模式得到Enviroment对象,并将Enviroment对象放入Configuration(全局java配置)对象中。

dataSourceElement()方法如下:

private DataSourceFactory dataSourceElement(XNode context) throws Exception {
   
    if (context != null) {
   
      String type = context.getStringAttribute("type");
      Properties props = context.getChildrenAsProperties();
      // 根据数据源类型获取对应类对象, 本文中type="POOLED",所以得到的对象为PooledDataSourceFactory
      DataSourceFactory factory = (DataSourceFactory) resolveClass(type).getDeclaredConstructor().newInstance();
      factory.setProperties(props);
      
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值