mybatis是什么
MyBatis 是一流的持久化框架,支持自定义 SQL、存储过程和高级映射。 MyBatis 消除了几乎所有的 JDBC 代码和手动设置参数和检索结果。 MyBatis 可以使用简单的 XML 或注解进行配置,并将原语、Map 接口和 Java POJO(Plain Old Java Objects)映射到数据库记录。
Mybatis是一个ORM类型的框架,解决的数据库访问和操作的问题,对现有的JDBC技术的封装。
官网地址:https://mybatis.org/mybatis-3/zh/index.html
mybatis和hibernate的对比看这个链接:https://blog.csdn.net/eff666/article/details/71332386
mybatis开发回顾
1、准备jar包
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>x.x.x</version>
</dependency>
2、配置配置文件mybatis-config.xml
mybatis-config.xml的配置:
<?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>
<!--别名的设置-->
<typeAliases>
<package name="domain.blog"/>
</typeAliases>
<!--环境的设置-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!--mapper的设置-->
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
XXMapper的配置:
<?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.mybatis.example.BlogMapper">
<select id="selectBlog" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper>
3、初始化配置
设置好应对的mybatis-config.xml中的数据源。
driver=com.mysql.cj.jdbc.Driver / com.mysql.jdbc.Driver
url=jdbc:mysql://localhost/bearweb?serverTimezone=Asia/Shanghai&zeroDateTimeBehavior=convertToNull&autoReconnect=true&useUnicode=true&characterEncoding=utf-8
username=root
password=123456
注意:注意mysql5.7以及mysql8版本的区别,一个不带cj,一个带cj。
4、开发步骤(7步编程)
- 创建表
- 创建entity
- 取类型别名
- DAO接口
- Mapper文件
- Mapper文件的注册
- API编程
mybatis数据存储类对象
在Java中或者JVM中对Mybatis相关的配置信息进行封装。
大家都知道,我们对文件的操作,是越少越好,因为文件的io操作很费内存,所以我们都是一次性读取,进而封装到配置对象中。
那Mybatis的配置文件有几种呢?
mybatis-config.xml ---> Configuration
xxxMapper.xml ---> MappedStatement
Configuration
public class Configuration {
// 对应environments标签的内容
protected Environment environment;
// 对应settings标签的内容
protected boolean safeRowBoundsEnabled;
protected boolean safeResultHandlerEnabled = true;
protected boolean mapUnderscoreToCamelCase;
protected boolean aggressiveLazyLoading;
protected boolean multipleResultSetsEnabled = true;
protected boolean useGeneratedKeys;
protected boolean useColumnLabel = true;
protected boolean cacheEnabled = true;
protected boolean callSettersOnNulls;
protected boolean useActualParamName = true;
protected boolean returnInstanceForEmptyRow;
// 对应settings标签的内容
protected String logPrefix;
protected Class<? extends Log> logImpl;
protected Class<? extends VFS> vfsImpl;
protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
protected JdbcType jdbcTypeForNull = JdbcType.OTHER;
protected Set<String> lazyLoadTriggerMethods = new HashSet<>(Arrays.asList("equals", "clone", "hashCode", "toString"));
protected Integer defaultStatementTimeout;
protected Integer defaultFetchSize;
protected ResultSetType defaultResultSetType;
protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
protected AutoMappingBehavior autoMappingBehavior = AutoMappingBehavior.PARTIAL;
protected AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior = AutoMappingUnknownColumnBehavior.NONE;
protected Properties variables = new Properties();
protected ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
protected ObjectFactory objectFactory = new DefaultObjectFactory();
protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
protected boolean lazyLoadingEnabled = false;
protected ProxyFactory proxyFactory = new JavassistProxyFactory(); // #224 Using internal Javassist instead of OGNL
protected String databaseId;
protected Class<?> configurationFactory;
protected final MapperRegistry mapperRegistry = new MapperRegistry(this);
protected final InterceptorChain interceptorChain = new InterceptorChain();
protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry(this);
protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection")
.conflictMessageProducer((savedValue, targetValue) ->
". please check " + savedValue.getResource() + " and " + targetValue.getResource());
protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");
protected final Map<String, ResultMap> resultMaps = new StrictMap<>("Result Maps collection");
protected final Map<String, ParameterMap> parameterMaps = new StrictMap<>("Parameter Maps collection");
protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<>("Key Generators collection");
protected final Set<String> loadedResources = new HashSet<>();
protected final Map<String, XNode> sqlFragments = new StrictMap<>("XML fragments parsed from previous mappers");
protected final Collection<XMLStatementBuilder> incompleteStatements = new LinkedList<>();
protected final Collection<CacheRefResolver> incompleteCacheRefs = new LinkedList<>();
protected final Collection<ResultMapResolver> incompleteResultMaps = new LinkedList<>();
protected final Collection<MethodResolver> incompleteMethods = new LinkedList<>();
protected final Map<String, String> cacheRefMap = new HashMap<>();
//.......
// 创建mybatis其他相关的对象
public MetaObject newMetaObject(Object object) {
return MetaObject.forObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
}
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
return parameterHandler;
}
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
ResultHandler resultHandler, BoundSql boundSql) {
ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
return resultSetHandler;
}
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
public Executor newExecutor(Transaction transaction) {
return newExecutor(transaction, defaultExecutorType);
}
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
//.......
}
有上面的源码我们可以看出,Mybatis主要在configuration中封装了如下内容:
- 封装了mybatis-config.xml相关的配置信息
- 封装了mapper文件,MappedStatement对象
- 创建了Mybatis其他相关的对象,像其他的一些Handler和executor之类对象
MappedStatement
public final class MappedStatement {
private String resource;
private Configuration configuration;
private String id;
private Integer fetchSize;
private Integer timeout;
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;
MappedStatement() {
// constructor disabled
}
public static class Builder {
private MappedStatement mappedStatement = new MappedStatement();
public Builder(Configuration configuration, String id, SqlSource sqlSource, SqlCommandType sqlCommandType) {
mappedStatement.configuration = configuration;
mappedStatement.id = id;
mappedStatement.sqlSource = sqlSource;
mappedStatement.statementType = StatementType.PREPARED;
mappedStatement.resultSetType = ResultSetType.DEFAULT;
mappedStatement.parameterMap = new ParameterMap.Builder(configuration, "defaultParameterMap", null, new ArrayList<>()).build();
mappedStatement.resultMaps = new ArrayList<>();
mappedStatement.sqlCommandType = sqlCommandType;
mappedStatement.keyGenerator = configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType) ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
String logId = id;
if (configuration.getLogPrefix() != null) {
logId = configuration.getLogPrefix() + id;
}
mappedStatement.statementLog = LogFactory.getLog(logId);
mappedStatement.lang = configuration.getDefaultScriptingLanguageInstance();
}
// .....
// 封装SQL mapper中的sql被封装成一个BoundSql对象
public BoundSql getBoundSql(Object parameterObject) {
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings == null || parameterMappings.isEmpty()) {
boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
}
// check for nested result maps in parameter mappings (issue #30)
for (ParameterMapping pm : boundSql.getParameterMappings()) {
String rmId = pm.getResultMapId();
if (rmId != null) {
ResultMap rm = configuration.getResultMap(rmId);
if (rm != null) {
hasNestedResultMaps |= rm.hasNestedResultMaps();
}
}
}
return boundSql;
}
}
对应的就是一个个的mapper文件中的配置。
例如:
-->MappedStatement
故一个mybatis中会有n个MappedStatement对象。
mybatis操作类对象
除了上述的存储类对象对配置文件进行存储,这还远远不够。我们在进行数据库操作的时候,还应该有操作类对象,就是操作数据库来完成功能。
站在数据库操作层面来看,我们的各种DAO + entity就是操作各种entity来进行数据存储。
而站在Mybatis层面来看,SqlSession会调用各种executor和handler来进行操作处理。
Executor
Executor是Mybatis中处理功能的核心,主要负责增删改和查的操作。
由Executor的基本结构可以看出:
- 完成增删改update操作以及查query的操作
- 关于事务之间的操作,包括事务的提交已经回滚
- 还有关于缓存之间的操作
那么问题来呢?Executor为什么要设计成接口呢?
一般的,和操作相关的都会设计成接口,这样的话。方便扩展。
Executor接口主要有三个实现,这三个实现可以在BaseExecutor的子类中找到:
- BatchExecutor:批量操作,一次连接,多次处理
- ReuseExecutor:复用的Executor,复用statement对象,当参数都一致时
- SimpleExecutor:常用的Executor
StatmentHandler
是Mybatis封装了JDBC Statment,真正Mybatis进行数据库访问操作的核心
功能:增删改查
也是用的适配器模式,BaseStatementHandler实现StatementHandler,而子类也有三个:
- CallableStatementHandler
- PreparedStatementHandler
- SimpleStatementHandler 进行JDBC操作
如果SimpleStatementHandler是解决数据库访问操作的,那么参数?又怎么处理呢?
ParameterHandler
目的:把Mybatis中的参数换成JDBC相关的参数
其实就是把@param注解中的#或者$换成JDBC中需要的'?'
ResultSetHandler
对JDBC中查询的结果集ResultSet进行封装
TypeHandler
对java中的数据类型和数据库中的数据类型进行转换
评论区