1、mybatis-config.xml
这个配置文件的结构如下:
properties
settings
typeAliases
typeHandlers
objectFactory
plugins
environments
transactionManager
dataSource
environment
databaseIdProvider
mappers
这里我简单说一说这些配置的意义,当然不可能每个都介绍的非常详细,我说说一些比较实用和比较常用的吧。
properties
这个其实是很多组件都会提供的一个配置功能,在这里可以可以定义一些属性,那么在这个文件的后面都可以使用${propertyName}
来引用这个属性,而且这里还可以引用外部文件,比如数据库连接信息,一般属于高密配置,不能直接写在配置文件里,那么可以单独写个配置文件config.properties
:
username=testpassword=123456 url=jdbc:mysql://localhost:3306/mybatis_study?useUnicode=true&characterEncoding=UTF-8&useLegacyDatetimeCode=false&serverTimezone=UTC&useSSL=false
然后在mybatis-config.xml
里配置:
<properties resource="config.properties"> <!--默认不开启--> <property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/> <!--默认就是:--> <property name="org.apache.ibatis.parsing.PropertyParser.default-value-separator" value="#|#"/> <property name="driver" value="com.mysql.cj.jdbc.Driver"/></properties>
那么,在后续的配置中可以引用这些属性:
<dataSource type="cn.dubby.mybatis.configuration.datasource.HikariCPDataSourceFactory"> <!--since MyBatis 3.4.2 如果driver没有找到,会使用冒号后的值作为默认值。此功能默认不开启,开启需指定org.apache.ibatis.parsing.PropertyParser.enable-default-value--> <property name="driverClassName" value="${driver#|#com.mysql.cj.jdbc.Driver}"/> <property name="jdbcUrl" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/></dataSource>
注意看,org.apache.ibatis.parsing.PropertyParser.enable-default-value
和org.apache.ibatis.parsing.PropertyParser.default-value-separator
这两个需要配合起来工作。作用是在使用${}
引用属性时,如果没有找到这个属性,可以使用一个默认值来代替,而属性名和默认值中间的分隔符就是这里配置的#|#
,默认是:
,使用时是${driver#|#com.mysql.cj.jdbc.Driver}
,意思就是没有没有配置driver
,那就使用com.mysql.cj.jdbc.Driver
。
如果即使用<property name="propertyName" value="propertyValue"/>
,又在config.properties
配置了propertyName
,那么该以哪个为准呢?
以config.properties
里配置的为准!
settings
先给出一个setting的配置选项吧,我们来感受一下:
<settings> <!--开启或禁用缓存--> <setting name="cacheEnabled" value="true"/> <setting name="lazyLoadingEnabled" value="true"/> <setting name="multipleResultSetsEnabled" value="true"/> <setting name="useColumnLabel" value="true"/> <setting name="useGeneratedKeys" value="false"/> <setting name="autoMappingBehavior" value="PARTIAL"/> <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/> <setting name="defaultExecutorType" value="SIMPLE"/> <setting name="defaultStatementTimeout" value="25"/> <setting name="defaultFetchSize" value="100"/> <setting name="safeRowBoundsEnabled" value="false"/> <!--数据库里下划线自动匹配成Java中驼峰命名的属性--> <setting name="mapUnderscoreToCamelCase" value="true"/> <setting name="localCacheScope" value="SESSION"/> <setting name="jdbcTypeForNull" value="OTHER"/> <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/></settings>
typeAliases
这是类型别名,因为Java中类的全限定名是包名+类名,太长啦,所以这里允许我们给他起个别名,这样在后面使用的时候,可以简短一点。
<typeAliases> <!--可以单独指定别名--> <typeAlias type="cn.dubby.mybatis.configuration.entity.Blog" alias="Blog"/> <!--也可以直接指定包下所有类的别名,此时还可以使用@Alias("blog")来修改他的别名--> <package name="cn.dubby.mybatis.configuration.entity"/></typeAliases>
可以一个类一个类的指定;也可以直接指定一个package,这样这个package下的所有的类都有别名了,此时你可以使用@Alias("blog")
来修改他的别名,默认就是类名。
typeHandlers
在MyBatis中,数据库中列转化成Object中的变量,都是TypeHandler
的转换成果。他是一个接口:
public interface TypeHandler<T> { void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException; T getResult(ResultSet rs, String columnName) throws SQLException; T getResult(ResultSet rs, int columnIndex) throws SQLException; T getResult(CallableStatement cs, int columnIndex) throws SQLException; }
MyBatis内置了很多TypeHandler
,如果我们需要自定义呢?这里给个简单的例子,如果在数据库中手机号存储格式如下:
image
但是在Java中,mobile是由countryCode和mobile共同决定的:
public class MobilePhone { private static final String DEFAULT_COUNTRY_CODE = "86"; private String countryCode; private String mobile; public MobilePhone(String mobile) { this(DEFAULT_COUNTRY_CODE, mobile); } public MobilePhone(String countryCode, String mobile) { this.countryCode = countryCode; this.mobile = mobile; } @Override public String toString() { return "'" + countryCode + "_" + mobile + "'"; } }
那么,我们可以自定义一个MobilePhoneHandler
:
@MappedJdbcTypes(JdbcType.VARCHAR)public class MobilePhoneHandler extends BaseTypeHandler<MobilePhone> { public void setNonNullParameter(PreparedStatement ps, int i, MobilePhone parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, parameter.toString()); } public MobilePhone getNullableResult(ResultSet rs, String columnName) throws SQLException { return convert(rs.getString(columnName)); } public MobilePhone getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return convert(rs.getString(columnIndex)); } public MobilePhone getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return convert(cs.getString(columnIndex)); } private MobilePhone convert(String mobileInDB) { if (mobileInDB == null || mobileInDB.trim().length() == 0) return null; String[] mobilePair = mobileInDB.split("_"); if (mobilePair.length != 2) { throw new IllegalArgumentException("mobile phone must be consist of countryCode and mobileNo."); } return new MobilePhone(mobilePair[0], mobilePair[1]); } }
然后别忘了需要配置这个TypeHandler
:
<typeHandlers> <!--可以单独指定别名--> <typeHandler handler="cn.dubby.mybatis.configuration.handler.MobilePhoneHandler"/> <!--也可以直接指定包下所有类的别名--> <package name="cn.dubby.mybatis.configuration.handler"/></typeHandlers>
那如果是枚举呢?
MyBatis给我们提供了两种枚举相关的TypeHandler:EnumTypeHandler
和 EnumOrdinalTypeHandler
。一看就知道,一个是根据名字转换(String),一个是根据顺序转换(int)。
默认MyBatis是使用名字转化的,也就是如果你的枚举是这样的:
public enum CategoryEnum { A, B; }
那么数据库中就存着A,B这样的字符串。但是很多DBA会建议我们使用Int来存储(性能,空间等各方面考虑),那么我们就需要使用EnumOrdinalTypeHandler
了。
<typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="cn.dubby.mybatis.configuration.enums.CategoryEnum"/>
可是,如果还想用String转换的方式呢,比如这种场景:
public class Category { private Integer id; private CategoryEnum category1; private CategoryEnum category2; }
那可以在ResultMap
在具体指定使用哪个来转换:
<resultMap id="CategoryResult" type="Category"> <result column="id" property="id"/> <result column="category1" property="category1"/> <result column="category2" property="category2" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/></resultMap>
Enum顺序是从0开始的
objectFactory
MyBatis每次创建一个对象来承载查询结果时,都会使用ObjectFactory来创建。我们可以重写这个类,来实现我们的目的:
public class ExampleObjectFactory extends DefaultObjectFactory { private static final Logger logger = LoggerFactory.getLogger(ExampleObjectFactory.class); public <T> T create(Class<T> type) { logger.info("ExampleObjectFactory create a object, type is {}", type.getName()); return super.create(type); } public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) { logger.info("ExampleObjectFactory create a object, type is {}", type.getName()); return super.create(type, constructorArgTypes, constructorArgs); } public void setProperties(Properties properties) { super.setProperties(properties); } public <T> boolean isCollection(Class<T> type) { return Collection.class.isAssignableFrom(type); } }
plugins
插件是MyBatis给我们开放的一个秘密通道,我们可以通过各个插件来拦截MyBatis生命周期里比较重要的一些方法调用:
Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
ParameterHandler (getParameterObject, setParameters)
ResultSetHandler (handleResultSets, handleOutputParameters)
StatementHandler (prepare, parameterize, batch, update, query)
这里给个例子吧:
@Intercepts({@Signature( type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})public class ExamplePlugin implements Interceptor { private Logger logger = LoggerFactory.getLogger(ExamplePlugin.class); public Object intercept(Invocation invocation) throws Throwable { logger.info("====intercept start===="); logger.info("参数:{}", invocation.getArgs()); Object result = invocation.proceed(); logger.info("结果:{}", result); logger.info("====intercept complete===="); return result; } public Object plugin(Object target) { return Plugin.wrap(target, this); } public void setProperties(Properties properties) { } }
配置插件:
<plugins> <plugin interceptor="cn.dubby.mybatis.configuration.plugin.ExamplePlugin"> <property name="someProperty" value="100"/> </plugin></plugins>
environments
先预览一下:
<environments default="development"> <environment id="development"> <transactionManager type="JDBC"> <property name="..." value="..."/> </transactionManager> <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>
首先我们看到一个environment
,还有一个default="development"
。这个作用是可以配置多个环境的数据源,每个envonment
有个名字,还可以设置一个默认的environment
,在构建SqlSessionFactory
的时候,可以指定envonment
:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);
如果不指定的话,就会使用默认的:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, properties);
注意:一个SqlSessionFactory只能选择一个environment
然后我们看到transactionManager
,这个MyBatis提供了两种内置的事务管理器,JDBC
和MANAGED
。这里不展开说,一般用JDBC
就可以了,而且如果使用Spring集成的话,Spring会使用自己的transactionManager
来替换MyBatis的transactionManager
。
然后就是DataSource了,MyBatis内置了三种:UNPOOLED
,POOLED
和JNDI
。这三个名字已经很明显了,我就不解释了,那如果想使用第三方的数据库连接池呢,该如何处理,简单的来说,可以自己实现DataSourceFactory
,我这里选择了据说是最快的HikariCP:
public class HikariCPDataSourceFactory implements DataSourceFactory { private HikariConfig config; @Override public void setProperties(Properties props) { config = new HikariConfig(props); } @Override public DataSource getDataSource() { return new HikariDataSource(config); } }
然后修改DataSource配置:
<dataSource type="cn.dubby.mybatis.configuration.datasource.HikariCPDataSourceFactory"> <property name="driverClassName" value="${driver#|#com.mysql.cj.jdbc.Driver}"/> <property name="jdbcUrl" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/></dataSource>
mappers
就是在这里配置所有的mapper,有这么几种选择:
<!-- 使用相对路径 --><mappers> <mapper resource="org/mybatis/builder/AuthorMapper.xml"/> <mapper resource="org/mybatis/builder/BlogMapper.xml"/> <mapper resource="org/mybatis/builder/PostMapper.xml"/></mappers>
<!-- 使用绝对路径 --><mappers> <mapper url="file:///var/mappers/AuthorMapper.xml"/> <mapper url="file:///var/mappers/BlogMapper.xml"/> <mapper url="file:///var/mappers/PostMapper.xml"/></mappers>
<!-- 使用接口全限定名 --><mappers> <mapper class="org.mybatis.builder.AuthorMapper"/> <mapper class="org.mybatis.builder.BlogMapper"/> <mapper class="org.mybatis.builder.PostMapper"/></mappers>
<!-- 使用包名 --><mappers> <package name="org.mybatis.builder"/></mappers>
2、XxxMapper.xml
mapper是MyBatis真正神奇的地方,这里让我们可以使用几乎原生的sql,但却又可以摆脱重复枯燥的jdbc拼接代码,让我们开始了解他吧,他的可以配置项分为:
cache – 在当前namespcae配置一个缓存
cache-ref – 从其他namespace引用一个缓存.
resultMap – 定义了如何把从数据库中查询出来的数据封装成Java的Object
parameterMap – Deprecated! 后续可能会删除,这里不解释
sql – 可重复使用的一段SQL
insert – 插入
update – 更新
delete – 删除
select – 选择
作者:我是杨正
链接:https://www.jianshu.com/p/8899d256177d
共同学习,写下你的评论
评论加载中...
作者其他优质文章