概述
全局配置 mybatis-config.xml
-
porperties属性
可以配置一些运行参数,可以放一些porperties或者xml文件,比如:
<properties> <property resource = "db.properties"></property> </properties>
-
settings设置
能够配置的内容比较多,能够影响Mybatis底层的运行,一般只修改一些常用的规则,比如自动映射、驼峰命名规则、级联规则、缓存、Executor类型等,比如:
<settings> <!--打印查询语句 --> <setting name = "logImpl" value = "STDOUT_LOGGING"/> <!--延迟加载开关,解决N+1问题,默认值为false--> <setting name = "lazyLoadingEnabled" value = "true"/> <!--层级加载开关,默认值3.4.1之后为false--> <setting name = "aggresiveLazyLoading" value = "true" /> <!--一级缓存开关,默认值session,也就是开启,修改值为STATEMENT则会关闭一级缓存--> <setting name = "localCacheScope" value = "SESSION"/> <!--二级缓存开关,默认开启,另外也可以在映射器中使用<cache/>标签进行开启,在特定的Sql标签修改useCache为false可以关闭该statement的二级缓存--> <setting name = "cacheEnabled" value = "true"/> </settings>
-
typeAliases类型别名
定义类的别名,简化使用,通常使用扫描的方式,如果别名重复使用注解@Aliases进行区分,比如:
<typeAliases> <typeAlias alias = "use" type = "com.xxx.User"></typeAlias> <package name = "com.xxx"/> </typeAliases>
-
typeHandlers类型转换器
将Java类型和Jdbc类型进行转换,有系统定义和自定义,自定义的需要实现BaseTypeHandler接口并且在这里进行注册,或者在映射器中指定,比如:
<!-- 配置文件中指定 --> <typeHandlers> <typeHandler handler = "com.xxx.typehandler.SexTypeHandler" javaType = "com.xxx.pojo.SexEnum" jdbcType = "INTEGER"/> <package name = "com.xxx.typehandler"/> </typeHandlers> <!-- 映射器中指定--> <resultMap id = "userResultMap" type = "user"> <result property = "sex" column = "sex" typeHandler = "com.xxx.typehandler.SexTypeHandler"></result> </resultMap>
-
objectFactory对象工厂
对象工厂是在创建结果集时通过反射来创建实例对象,可以通过实现ObjectFactory接口或者继承DefaultObjectFactory来自定义返回规则,通常不需要配置,
<ObjectFactory type = "com.xxx.objectfactory.MyObjectFactory"> <property name = "" value = ""></property> </ObjectFactory>
-
plugin插件
Mybatis中的插件拦截的四个对象Executor、ParameterHandler、ResultSetHandler、StatementHandler,自定义的插件需要实现Interceptor接口,并且在配置中注册。关于插件的运行原理和分页插件的使用在后续文章中在写。
-
enviroments运行环境
主要是配置数据库信息,可以配置多个数据库,一般而言只需要配置一个就行了。包括了事务管理器和数据源
事务管理器:Mybatis提供了两个工厂类,:JdbcTransactionFactory和ManagedTransactionFactory,JDBC以jdbc的方式对数据库的提交和回滚进行操作,而MANAGED把事务交给容器处理,提交和回滚方法不用任何操作,默认情况下会关闭连接。
数据源:提供了PooledDataSourceFactory、UnpooledDataSourceFactory、JndiDataSourceFactory三个工厂类,POOLED使用连接池的思想对Connection管理;UNPOOLED采用非数据库连接池的管理方式,每次请求都会打开一个新的数据库连接;JNDI是为了能在如EJB或者应用服务器这类容器中使用。
在与Spring集成之后数据库连接和事务都托管给了Spring。
<environments default="development"> <environment id="development"> <transactionManager type="JDBC"></transactionManager> <dataSource type="POOLED"> <property name="driver" value=""/> <property name="url" value=""/> <property name="userName" value=""/> <property name="password" value=""/> </dataSource> </environment> </environments>
-
databaseIdProvider数据库厂商标识
查询时可以支持多数据库,当SQL语句中的databaseID被配置了的时候,系统会优先取和数据库配置一致的SQL,如果没有,则取没有databaseID的SQL执行,可以把它当做默认值,value为数据库别名,可以通过这个别名标注那一条SQL语句适用于哪种数据库运行,比如:
<databaseIdProvider type="DB_VENDOR"> <property name="MySQL" value="mysql"/> <property name="Oracle" value="oracle"/> <property name="DB2" value="db2"/> </databaseIdProvider> <select id = "getUserById" parameterType = "int" resultType = "user" databaseId = "mysql"> select id uname as name note from t_user where 1 = 1 and id = #{id} </select> <select id = "getUserById" parameterType = "int" resultType = "user" databaseId = "oracle"> select id uname as name note from t_user where id = #{id} </select> <!-- 这样当数据库切换时,就会自动选择对应的sql进行查询-->
-
mapper映射器
映射器namespace = 接口的权限名,SELECT|UPDATE|INSERT|DELETE标签的id则对应接口的方法名,映射器的引入通常有下面几种方法:
<mappesr> <!--使用类名注册--> <mapper class = "com.xxx.mapper.UserMapper"/> <!--使用包名注册,常用--> <package name = "com.xxx.mapper"/> <!--使用文件路径引入--> <mapper resource = "com/xxx/mapper/UserMapper.xml"/> </mappers>
和spring集成之后映射器的扫描托管到spring的配置文件中,在springboot中则使用注解@MapperScan(“packagename”)进行扫描。
Mapper映射器
-
缓存cache
跟Hibernate一样,Mybatis也有一级缓存和二级缓存,并且预留了集成第三方缓存的接口。
Mybatis跟缓存相关的类都在cache包中,定义了一个Cache接口,并且只有一个默认的实现类PerpetualCache底层使用HashMap实现,这个对象一定会创建,也叫基础缓存,除此之外,Mybatis还定义了很多缓存的装饰器,通过这些装饰器,可以对基础缓存扩展很多额外的功能,比如回收策略、日志记录、定时刷新等。总体上分三类:基本缓存,淘汰算法缓存、装饰器缓存。下面对这些缓存做个说明:
缓存实现类 描述 作用 装饰条件 基本缓存 缓存基本实现类 默认是PerpetualCache,也可以自定义比如RedisCache/EhCache等具备基本功能的缓存类 无 LruCache LRU策略的缓存 删除最近最少使用的缓存 eviction=“LRU”(默认) FifoCache FIFO策略的缓存 删除最先入队的缓存 eviction=“FIFO” SoftCache WeakCaceh 带清理策略的缓存 通过JVM的软引用和弱引用来实现缓存,当JVM内存不足时,会自动清理这些缓存,基于SoftReference和WeakReference eviction=“SOFT|WEAK” LoggingCache 带日志功能的缓存 比如:输出缓存命中率 基本 SynchronizedCache 同步缓存 基于Synchronized关键字实现,解决并发问题 基本 BlockingCache 阻塞缓存 通过在get/put方式中加锁,保证只有一个线程操作缓存,基于JAVA重入锁实现 bloking=“true” SerializedCache 支持序列化的缓存 将对象序列化以后存入缓存,取出时反序列化 readOnly=false(默认) ScheduledCache 定时调度的缓存 在进行get/put/remove/getSize等操作前,判断缓存时间是否超过了设置的最长缓存时间(默认是1小时),如果是则清空缓存,也就是每隔一段时间清空一次缓存 flushInterval不为空 TransactionalCache 事务缓存 在二级缓存中使用,可一次存入多个缓存,移除多个缓存 在TransactionalCacheManager中用Map维护对应关系 -
一级缓存
一级缓存也叫本地缓存Local Cache,是SqlSession层面的缓存,默认开启。既然是在SqlSession中进行缓存,DefaultSqlSession中只有两个对象属性:Configuration和Executor,而前者是全局性的,所以一级缓存是在Executor中维护的,三种执行器的父类BaseExecutor中的构造函数中就初始化了PerPetual对象。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gy0PLLM3-1592171443328)(C:UsersdellDesktop学习资料markdownmarkword-imgimage-20200615051703746.png)]
在同一个Session中共享,不同Session不能共享。
一级缓存的存入:是在BaseExecutor的query()方法中的queryFromDataBase()方法中存入的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IYdnuVZa-1592171443331)(C:UsersdellDesktop学习资料markdownmarkword-imgimage-20200615042308068.png)]
一级缓存的清空:同一个会话中,更新或者删除操作会导致缓存被清空,如果select标签的flushCache=true时,则查询也会清空缓存。在BaseEexcutor中的update()方法中调用了clearLocalCache()方法来清空。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JYg63oOB-1592171443333)(C:UsersdellDesktop学习资料markdownmarkword-imgimage-20200615042649393.png)]
一级缓存存在的问题:如果其他会话更新数据,会导致本会话从缓存中读取到过时的数据。要解决这个问题只能用范围更大的二级缓存。
-
二级缓存
二级缓存是用来解决一级缓存不能跨会话共享的问题的,是namespace级别的,只要是同一个接口里面相同的方法,都可以共享,声明周期和应用同步。
如果开启了二级缓存,那么使用到缓存的时候,肯定是先查询二级缓存,二级缓存没有的时候才去一级缓存中查,一级缓存没有的时候就到数据库去查。
一级缓存是放在Executor中的,二级缓存的范围比它大,Mybatis中对Executor做了个装饰,使用CashingExecutor来维护,也就是如果使用二级缓存,则在创建Executor对象时会对Executor进行装饰,查询时判断CashingExecutor中是否有缓存结果,有就从该缓存中返回,没有就委派给真正的执行器执行查询,比如说SimpleExecutor,再到该执行器中的一级缓存中查。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kl7nDI5s-1592171443336)(C:UsersdellAppDataRoamingTyporatypora-user-imagesimage-20200615054152012.png)]
注意:全局配置文件中二级缓存的总开关默认开启,如果一个Mapper要使用二级缓存,还要单独打开它自己的开关。
<!-- mapper中声明该namespace使用二级缓存--> <cache type = "org.apache.ibatis.cache.impl.PerpetualCache" size = "1000" eviction = "LRU" flushInterval = "12000" readOnly = "false"/> <!-- size表示最多缓存的对象个数,eviction表示回收策略,flushInterval表示自动刷新时间-->
-
-
select
首先来看一个简单的使用:
-
简单说一下各个属性的含义:namespace为接口的全限定名,id为接口中对应的方法,parameterType为传入参数的类型,resultType为结果映射的类型…
-
多个参数的传递方式:使用map,使用注解,使用javabean。
使用map:代码可读性降低,用的比较少
List<Employee> selectByMap(Map<String,Object> map);
使用注解:一般参数少于5个时,简单使用,可读性高,参数过多调用起来不方便,显得繁琐复杂 ```java
List selectByAnnotation(@Param(“name”)String name,@Param(“lastNumber”)int lastNumber);
``````xml <select id = "selectByMap" resultType = "emploee"> select emp_id as id name mobile note from t_emp where name like concat('%',#{name},"%") and mobile like concat('%',#{lastNumber},'%') </select> ``` 使用javabean:参数多于5个时使用比较方便 ```java public class EmploeeParam{ private String name; private int lastNumber; ...
}
```
select emp_id as id name mobile note from t_emp where name like concat('%',#{name},"%") and mobile like concat('%',#{lastNumber},'%') ``````xml
- 分页参数RowBounds
RowBounds是Mybatis内置的分页类,有两个参数,offset表示从哪一行开始,limit表示限制条数,在接口方法上加上这个参数直接使用,比如:
List<Employee> selectByAnnotation(@Param("name")String name,@Param("lastNumber")int lastNumber,RowBounds rb); @Autowired private EmployeeService service; @RequestMapping("/emps_like") @ResponseBody public ModelAndView getEmps(@RequestParam("name")String name,@RequstParam("lastNumber")int lastNumber) { ModelAndView mv = new ModelAndView(); RowBounds rb = new RowBounds(0,10); List<Employee> list = service.selectByAnnotation(name,lastNumber,rb); mv.put("emps",list) return mv; } ``` 3. #### insert - 简单的使用 ```xml <mapper namespace = "com.xxx.dao.EmployeeMapper"> <insert id = "insertEmp" parameterType = "employee"> insert into t_emp(emp_id,name, sex,mobile, note) values(#{id},#{name},#{sex},#{mobile},#{note}) </insert> </mapper> ``` - 主键回填 无论支持还是不支持主键自增的数据库都可以使用selectKey来实现主键回填,比如: ```xml <!--mysql 注意order要设置为after,获取递增主键值用的是函数LAST_INSERT_ID()--> <insert id="insertUser" parameterType="user" > <selectKey keyProperty="id" order="after " resultType="int" > select LAST_INSERT_ID() </selectKey> insert into t_user(t_name,sex) values (#{name},#{sex}) </insert> <!--oracle 注意order要设置为before,因为要先从序列中获取值,然后将值作为主键插入到数据库中--> <insert id="insertUser" parameterType="user" > <selectKey keyProperty="id" order="before " resultType="int" > select t_id.nextval as id from dual </selectKey> insert into t_user(t_id,t_name,sex) values (#{t_id},#{name},#{sex}) </insert> ``` 对于支持自增主键的数据库MySQL,也可以使用下面这种方式实现主键回填,设置useGeneratedKeys属性为true,keyProperty设置生成主键映射到那个属性上,keyColum是映射到那个字段上。 ```java void insertUser(User user); ``` ```xml <insert id="insertUser" parameterType="user" useGeneratedKeys="true" keyProperty="id"> insert into t_user(t_name,sex) values (#{name},#{sex}) </insert> ``` 对于不支持主键自增的数据库Oracle,就通过通用方式selectKey属性和标签来完成。 这里对selectKey标签中的属性简单说明一下: | 属性 | 描述 | | ------------- | ------------------------------------------------------------ | | keyProperty | selectKey语句结果应该被设置的目标属性 | | resultType | 结果的类型 | | keyColumn | 匹配属性的返回结果集中的列名称 | | order | 如果为before,那么它会先执行selectKey语句设置keyProperty然后执行插入语句,如果为after则相反 | | statementType | 使用哪种语句类型,默认为PREPARED。 | 4. #### update|delete 这两个比较简单,对于批量更新和删除见后面的动态sql一节。 5. #### resultMap resultMap主要用途有两个:第一个就是当数据库字段名和Java对象属性名不一致是使用,第二个就是用于高级查询,也就是一对多,多对多。代码示例: ```xml <resultMap id="employee" type="employee"> <id column="id" property="id"/> <!-- 主键列--> <result column="real_name" property="realName"/> <result column="sex" property="sex"/> <result column="birthday" property="birthday"/> <result column="mobile" property="mobile"/> <result column="email" property="email"/> <result column="POSITION" property="position"/> <result column="note" property="note"/> <!-- association完成一对一的映射--> <association property="workCard" column="id" select="com.dao.WorkCardDao.getWorkCardByEmpId"/> <!-- collection完成一对多的映射--> <collection property="employeeTaskList" column="id" fetchType="lazy" ofType="employeeTask" select="com.dao.EmployeeTaskDao.getEmployeeTaskByEmpId"/> <!--鉴别器--> <discriminator javaType="long" column="sex"> <case value="1" resultMap="maleHealthFormMapper"/> <case value="0" resultMap="femaleHealthFormMapper"/> </discriminator> </resultMap> <resultMap id="maleHealthFormMapper" type="maleEmployee" extends="employee"> <association property="maleHealthForm" column="id" select="com.dao.MaleHealthFormDao.getMaleHealthForm"/> </resultMap> <resultMap id="femaleHealthFormMapper" type="femaleEmployee" extends="employee"> <association property="femaleHealthForm" column="id" select="com.dao.FemaleHealthFormDao.getFemaleHealthForm"/> </resultMap> <select id="getEmployee" parameterType="long" resultMap="employee"> select id,real_name as realName,sex,birthday,moblie,email,POSITION,note from t_emploee where id = #{id} </select>
-
sql片段
通常是把一些反复使用的SQL片段比如列名,定义在sql标签中,在其他标签中就可以通过引入的方式使用,比如:
<sql id = "empCols"> id,real_name,sex,birthday,moblie,email,POSITION,note </sql> <select id="getEmployee" parameterType="long" resultMap="employee"> select <include refid = "empCols"/> <!--引入--> from t_emploee where id = #{id} </select>
另外sql标签还支持变量传递,比如:
<sql id = "empCols"> ${alias}.id,${alias}.real_name,${alias}.sex,${alias}.birthday,${alias}.moblie,${alias}.email,${alias}.POSITION,${alias}.note </sql> <!--定义的alias变量的值就是表的别名--> <select id="getEmployee" parameterType="long" resultMap="employee"> select <include refid = "empCols"> <property name = "alias" value = "e"></property> </include> from t_emploee e where id = #{id} </select>
-
级联查询
Mybatis中的级联分三种:鉴别器、一对一和一对多,分别对应着resultMap中的:discriminator、association和collection属性,
-
嵌套查询:会多执行一些SQL语句导致数据库资源的损耗和系统性能的下降,也就是N+1问题,解决方案就是打开延迟加载开关:
<resultMap id="employee" resultType = "employee"> <association property="workCard" column="id"select="com.xxx.dao.WorkCardDao.getWorkCardByEmpId"/> <collection property="employeeTaskList" column="id" fetchType="lazy" select="com.xxx.dao.EmployeeTaskDao.getEmployeeTaskByEmpId"/> </resultMap> <!--就是在查询employee表的时候通过select属性值(statementId)定位到另外的一个查询上,进行了第二次查询,看上去只有一个查询雇员信息的操作,其实后台分别执行了对雇员表、工号表、雇员任务表的查询 --> <!--解决方案: 1.全局性配置:lazyLoadingEnabled是否开启延迟加载,aggressiveLazyLoading是否采用层级加载。 2.语句配置:fetchType属性可以处理全局定义无法处理的问题,进行自定义。注意该选项只在级联元素association和collection中存在,fetchType=eager 获得当前POJO后立即加载对应的数据,fetchType=lazy 获得当前POJO后延迟加载对应的数据 注意:如果配置了fetchType属性,那么它会忽略上述的两个全局配置项。 -->
-
嵌套结果查询:基于表连接实现级联,会导致SQL变复杂,所需要的配置也比较复杂,一次性取出所有数据会造成内存浪费,给日后的维护工作带来不便,一般用于比较简单,关联不多的场景下。
<resultMap id="employee2" type="employee"> <id column="id" property="id"/> <result column="real_name" property="realName"/> <result column="sex" property="sex"/> <result column="brithday" property="birthday"/> <result column="mobile" property="mobile"/> <result column="email" property="email"/> <result column="position" property="position"/> <association property="workCard" javaType="workCard" column="id"> <id column="wc_id" property="id"/> <result column="id" property="empId"/> <result column="wc_real_name" property="realName"/> <result column="wc_department" property="department"/> <result column="wc_mobile" property="mobile"/> <result column="wc_position" property="position"/> <result column="wc_note" property="note"/> </association> <collection property="employeeTaskList" ofType="employeeTask" column="id" > <id column="et_id" property="id"/> <result column="id" property="empId"/> <result column="et_task_name" property="taskName"/> <result column="et_note" property="note"/> <association property="task" javaType="task" column="et_task_id"> <id column="t_id" property="id"/> <result column="t_title" property="task.title"/> <result column="t_context" property="task.context"/> <result column="t_note" property="note"/> </association> </collection> <discriminator javaType="int" column="sex"> <case value="1" resultMap="maleEmployeeMapper2"/> <case value="0" resultMap="femaleEmployeeMapper2"/> </discriminator> </resultMap>
-
动态SQL
-
概念:动态Sql可以让我们在xml映射文件中以标签的形式编写动态sql,完成逻辑判断和动态拼接Sql的功能。
-
九中动态Sql标签:if|where|set|foreach|choose|when|otherwise|trim|bind
具体使用方法后面文章在写
-
执行原理:使用OGNL从Sql参数对象中计算表达式的值,根据表达式的值动态拼接Sql。
-
动态SQL
-
概念:动态Sql可以让我们在xml映射文件中以标签的形式编写动态sql,完成逻辑判断和动态拼接Sql的功能。
-
九中动态Sql标签:if|where|set|foreach|choose|when|otherwise|trim|bind
具体使用方法后面文章在写
-
执行原理:使用OGNL从Sql参数对象中计算表达式的值,根据表达式的值动态拼接Sql。
最后
以上就是玩命小伙为你收集整理的mybatis的两大配置文件的全部内容,希望文章能够帮你解决mybatis的两大配置文件所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复