Mybatis有什么用
Mybatis是一个ORM(Object Relational Mapper/对象相关映射)框架,可同时支持多数据源,通过封装JDBC,提供了对象和记录的转换,连接数据库,以及完成记录在数据库的操作。
使用
注意
由于springboot的出现,配置文件可以不写了,这里留下只是为了后续Configuration解析不抽象。
Mybatis的配置文件
1 数据源
通过environment,可以配置多个数据源,并且可以指定默认数据源
如果sql语句不想走默认数据源,需要在sql语句上注明数据源的选择
2 别名
提供了实体类的别名,这样在Mapper中使用时就不需要写全限定名了
3 Mapper文件位置
Mapper文件是sql语句的具体放置位置,通过文件位置,Mybatis可以找到所有Mapper文件
以下是网上随便找的一个demo
<?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>
<!-- 默认使用的环境 ID(比如:default="development")
也就是说我们可以配置多套<environment>环境-->
<environments default="development">
<!--
每个 environment 元素定义的环境 ID
-->
<environment id="development">
<!--
transactionManager 事务管理器
type的值有JDBC和MANAGED
JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
-->
<transactionManager type="JDBC"/>
<!--
dataSourcedataSource 数据源 dbcp c3p0 druid
type="[UNPOOLED|POOLED|JNDI]"
POOLED意思有连接池的连接
UNPOOLED意思没有连接池的连接
-->
<dataSource type="POOLED">
<!-- JDBC 驱动-->
<property name="driver" value="${driver}"/>
<!-- url数据库的 JDBC URL地址。-->
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
<!-- defaultTransactionIsolationLevel – 默认的连接事务隔离级别。–>-->
<!-- <property name="defaultTransactionIsolationLevel" value=""/>-->
<!-- defaultNetworkTimeout – 等待数据库操作完成的默认网络超时时间(单位:毫秒)–>-->
<!-- <property name="efaultNetworkTimeout" value=""/>-->
</dataSource>
</environment>
</environments>
<mappers>
<!-- 使用相对于类路径的资源引用 -->
<!-- <mapper resource="asia/xiaojiang/mybatis03/dao/UserMapper.xml"/>-->
<!-- 使用完全限定资源定位符(URL)
不推荐使用
<mapper url="E:\JetBrains\mybatis学习\Mybatis-study\Mybatis-03\src\main\java\asia\xiaojiang\mybatis03\dao\UserMapper.xml"/>
-->
<!-- 使用映射器接口实现类的完全限定类名
使用注意点:
接口和其配置文件必须同名, 必须在同一个包下
-->
<mapper class="asia.xiaojiang.mybatis03.dao.UserMapper"/>
<!-- 将包内的映射器接口实现全部注册为映射器
使用包扫描注意点:
接口和其配置文件必须同名, 必须在同一个包下
-->
<!-- <package name="asia.xiaojiang.mybatis03.dao"/>-->
</mappers>
</configuration>
Mybatis操作基本步骤
1 创建表
2 创建实体类
3 创建DAO接口类,定义需要的sql操作接口
4 创建Mapper文件,命名空间指向DAO接口类
使用之下
Mybatis的实质
提供缓存与其它机制,使用XpathParser作为XML读取工具,读取XML,初始化数据,并使用完成SqlSession的创建,调用SqlSession通过JDBC完成底层数据库查询
//首先读取并解析xml文件,把xml内容加载进工厂
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//使用工厂生成自带属性的数据库连接
SqlSession sqlSession = sqlSessionFactory.openSession();
//JDK动态代理技术,动态生成一个UserDao接口的实现类
UserDAO userDAO = sqlSession.getMapper(UserDAO.class);
List<User> users = userDAO.queryAllUsers();
初始化数据结构
配置类Configuration
Mybatis在一开始就完成静态文件的读取。
org.apache.ibatis.session.Configuration是mybatis-config.xml和里面指向的Mapper的对象封装型。
除了初始化变量,它还定义了connection,statement,resultset的实例化方法
以下是它所有完成的初始化变量
//配置类的数据源信息保存
protected Environment environment;
//配置类其它setting
protected boolean safeRowBoundsEnabled;
protected boolean safeResultHandlerEnabled;
protected boolean mapUnderscoreToCamelCase;
protected boolean aggressiveLazyLoading;
protected boolean multipleResultSetsEnabled;
protected boolean useGeneratedKeys;
protected boolean useColumnLabel;
protected boolean cacheEnabled;
protected boolean callSettersOnNulls;
protected boolean useActualParamName;
protected boolean returnInstanceForEmptyRow;
protected boolean shrinkWhitespacesInSql;
protected boolean nullableOnForEach;
protected String logPrefix;
protected Class<? extends Log> logImpl;
protected Class<? extends VFS> vfsImpl;
protected Class<?> defaultSqlProviderType;
protected LocalCacheScope localCacheScope;
protected JdbcType jdbcTypeForNull;
protected Set<String> lazyLoadTriggerMethods;
protected Integer defaultStatementTimeout;
protected Integer defaultFetchSize;
protected ResultSetType defaultResultSetType;
protected ExecutorType defaultExecutorType;
protected AutoMappingBehavior autoMappingBehavior;
protected AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior;
protected Properties variables;
protected ReflectorFactory reflectorFactory;
protected ObjectFactory objectFactory;
protected ObjectWrapperFactory objectWrapperFactory;
protected boolean lazyLoadingEnabled;
protected ProxyFactory proxyFactory;
protected String databaseId;
protected Class<?> configurationFactory;
//配置类的Mapper信息保存
protected final MapperRegistry mapperRegistry;
protected final InterceptorChain interceptorChain;
protected final TypeHandlerRegistry typeHandlerRegistry;
//配置类的实体类别名设置
protected final TypeAliasRegistry typeAliasRegistry;
protected final LanguageDriverRegistry languageRegistry;
//与mapper有关
protected final Map<String, MappedStatement> mappedStatements;
protected final Map<String, Cache> caches;
//resultMap和parameterMap的承装,String为DAO全限定名+sql的id来保证唯一
protected final Map<String, ResultMap> resultMaps;
protected final Map<String, ParameterMap> parameterMaps;
protected final Map<String, KeyGenerator> keyGenerators;
protected final Set<String> loadedResources;
protected final Map<String, XNode> sqlFragments;
protected final Collection<XMLStatementBuilder> incompleteStatements;
protected final Collection<CacheRefResolver> incompleteCacheRefs;
protected final Collection<ResultMapResolver> incompleteResultMaps;
protected final Collection<MethodResolver> incompleteMethods;
protected final Map<String, String> cacheRefMap;
Mapper的sql信息承装
MappedStatement用来承装单条sql的信息
private String resource;
//拥有一个指回的Configuration
private Configuration configuration;
private String id;
private Integer fetchSize;
private Integer timeout;
//分为callable(存储过程使用),prepared(prepareStatement),statement,
private StatementType statementType;
private ResultSetType resultSetType;
private SqlSource sqlSource;
private Cache cache;
private ParameterMap parameterMap;
private List<ResultMap> resultMaps;
private boolean flushCacheRequired;
private boolean useCache;
private boolean resultOrdered;
private SqlCommandType sqlCommandType;
private KeyGenerator keyGenerator;
private String[] keyProperties;
private String[] keyColumns;
private boolean hasNestedResultMaps;
private String databaseId;
private Log statementLog;
private LanguageDriver lang;
private String[] resultSets;
执行过程
初始化信息的加载
在new SqlSessionFactoryBuilder().build(inputStream)中,不仅完成了对mybatis-config.xml的解析,同时完成了其中mapper的解析。在这个方法中,mybatis-config.xml被解析为了Configuration,mapper.xml被解析为了MappedStatement,作为SqlSessionFactory的初始属性。
XML解析工具
使用了XpathParser,将XML标签解析为一个个XNode节点,并提供eval作为节点目录的访问,比如eval(“/*”)会返回所有XML一级标签
代理的封装
userDAO.queryAllUsers()实际上是对sqlSession.selectList(“com.baizhiedu.dao.UserDAO.queryAllUsers”)的封装。
之所以使用了代理模式封装,是因为表达概念更清晰,使用了对象,既方便查看,有条理清晰,好过字符串 ,而且在编程上方便很多。
userDAO.queryAllUsers()的调用中,实际上会使用invokeHandler的方法,根据userDao全限定名+方法名作为key,去查询Configuration中MappedStatements,获取对应XML中对应方法的各种标签参数,外层只是一个空实现。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
return Object.class.equals(method.getDeclaringClass()) ? method.invoke(this, args) : this.cachedInvoker(method).invoke(proxy, method, args, this.sqlSession);
} catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
}
SqlSession底层调用
SqlSession是一次对数据库的Connection,它屏蔽了下层的具体实现,只提供了类似select,update,insert这样的接口,给上层反复调用。
以下是SqlSession提供的操作接口
在SqlSession创建时,就会根据ExecType创建自己独有的Excecutor
Executor主要任务是,完成sql执行,完成事务提交与回滚操作,完成sql缓存的保存
Executor是经典的模板模式,BaseExecutor实现了Executor接口,在增删查改的方法中实现了对一级缓存的更新,并留下抽象方法等子类来实现。SimpleExecutor,ReuseExecutor,BatchExecutor都是它的实现类。
StatementHandler是Executor内部用于完成sql执行的工具,它有着具体sql参数ParameterHandler和承装结果的结果集ResultSetHandler。
TypeHandler不从属于某一个Executor,它提供Java和数据库类型的转化,比如Java的int和数据库的int