配置文件中类的全名用.分隔 xml文件的名字用/分隔
手动配置mybatis的步骤:
需要先配置mybatis.xml,mybatis.xml里面的<mappers>标签用来加载映射文件
然后写实体类和实体类对应的mapper(映射)文件(可自动生成)
编写测试类测试:
加载Mybayis.xml配置文件,利用Resources类将配置文件转化为流的形式
Reader reader = Resources.getResourceAsReader("mybatis.xml");
构建SqlSessionFactory对象(实例化)
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
//SqlSessionFactory是一个接口,没有构造方法,不能直接new,需要用他的对象SqlSessionFactoryBuilder()
session相当于之前的connection,需要用他访问数据库
SqlSession session = sessionFactory.openSession();
String statement = "mapper.xml的namespace + 增删查改方法的id";
Object oject = session.selectOne(statament,1); //1是参数,要和mapper的paramType对应
session.close();
session.selectOne底层是mybatis用动态代理(代理模式) 来实现。也有人称接口开发
mybatis.xml各标签的作用:
mybatis.xml里面的<mappers>标签用来加载映射文件。
<properties resource="db.properties">用来加载数据库的配置信息。通过${driver}可以取到。
<settings>可以设置全局参数,也可以控制各种功能的开启和关闭(日志,缓存,延迟加载等)
//配置类型转换器(mybatis自带很多类型转换器,但也可自定义)
<typeHandlers>
<typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>
</typeHandlers>
自定义转换器需要实现TypeHandler接口,但是TypeHandler接口比较复杂,所以可以继承他的实现类BaseTypeHandler。
<environments default='environment的id'>下可以配置多个<environment>,每个都是一个环境,可以是开发环境,测试环境,上线后的运行环境等等。通过修改default的值来选择不同的环境。
也可以在SqlSessionFactoryBuilder().build()方法中添加一个参数强行修改数据库运行环境。
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader,environment的id);//environment的id指定数据库运行环境,即使配置文件default没有配置,也可以强制选择。
<environment>下的<datasource type="">标签用来配置数据源,数据源类型有以下几种:
1.POOLED (使用数据库连接池),只需要取连接,用完还回到连接池,不需要每次都打开关闭连接。
2.UNPOOLED(不使用连接池),每次访问都需要打开和关闭连接,消耗性能。
3.JNDI(使用tomcat内置连接池),也是连接池,但是是自带的,不是第三方的
<environment>下的<transactionManager type="">标签用来配置事务提交方式:
1.JDBC: 利用JDBC方式处理事务,需要手动(commit,rollback,close)
2.MANAGED:将事务交给其他组件去托管,自动,(Spring,jboss),默认会关闭连接。
可以通过在<transactionManager type="">标签里配置
<property name="closeConnection" value="flase" /> //取消自动关闭
mapper.xml各标签的作用:
mybatis.xml里面的<mappers>标签用来加载映射文件。
<mapper namespace="该mapper.xml的全称,不带后缀"> //该namespace就是这个mapper文件的唯一标识
mybatis约定输入参数parameterType 和 输出参数resultType形式上只能有一个。
如果parameterType是简单类型(八个基本数据类型+String),预编译形式可以用任何占位符#{XXX},${value}$符号只能是value,{}里面必须是value。
#{}会自动给String类型加上单引号'' 但是${},原样输出,不会加单引号。动态排序的字段只能用${}
如果parameterType是对象类型,则必须是对象的属性。#{属性名},${属性名}
如果返回结果是对象类型,不管是返回一条数据还是多条数据,resultType='对象全称'(不是List)
如果parameterType是Map,则stuname=#{stuname},用map中的key来匹配占位符#{stuname},如果可以匹配,则用map中这个key的value值替换占位符
查询类中的属性类型和表中的字段类型能够合理识别(String-varchar2)或者一一对应(stuNo-stuno),使用resultType,否则(boolean-Integer)使用resultMap。(也可以用resultType+HashMap来替换resultMap)
如果用resultMap,则需要<resultMap></resultMap>配置映射关系,jdbcType="INTEGER" 这里的INTEGER必须要大写。
调用存储过程:首先需要给数据库写一个存储过程(需要传入的参数和传出的结果)。statementType="CALLABLE"决定了sql的执行方式是存储过程。mybatis调用存储过程的时候一般传入Map,通过map的put方法传入输入参数的值,通过get方法获取输出参数的值。CALL后面跟存储过程的名称,具体格式如下。但是要注意低版本的驱动可能会不支持空格和换行。可以把调用存储过程写在一行,或者换一个较高版本的驱动。
<foreach>迭代的类型为对象的属性时,实现sql中where stuNo in(1,2,3)这样的效果。
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT * FROM POST P
<where>
<foreach item="stuNo" collection="stuNos"
open="ID in(" separator="," close=")">
#{stuNo}
</foreach>
</where>
</select>
//<foreach>中的item属性要和#{stuNo}中{}里面的内容对应
//如果要迭代的类型是简单类型(八个基本数据类型和String)数组,collection="array"
//如果要迭代的类型是集合,collection="list"
//如果传递的是对象数组,则collection="Object[]",item="对象(student)",#{对象的属性(student.stuNo)}
一对一关联查询时:
返回结果为两个关联表的字段,但是JAVA只能单继承,所以可以写一个业务扩展类,实现属性多的类,再自己加上属性少的类,resultType就是这个包含两个类字段的业务扩展类。
也可以通过resultMap实现,需要配置映射关系,如下:
一对多,多对一,多对多关联查询时:
通过resultMap实现,需要配置映射关系,如下:
延迟加载:
在<resultMap>配置中添加select="namespace+sql的Id" column="关联的列名"。
mybatis中使用延迟加载,需要先配置:
<settings>
<!--开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true">
<!--关闭立即加载-->
<setting name="aggressiveLazyLoading" value="false">
</settings>
查询缓存:
一级缓存:同一个sqlSession对象。
mybatis默认开启一级缓存,第一次查询会访问数据库,获取到结果。然后将结果放入内存(缓存),确切点是sqlSession对象中,之后的第N次查询都直接从sqlSession中获取对象,不需要再次和数据库建立连接,从数据库查询(和数据库建立连接,关闭连接会消耗性能)。执行commit()操作会清理所有的缓存对象(将查询结果从sqlSession中移除)。
二级缓存:
mybatis自带缓存:同一个namespace。如果多个mapper.xml文件共享一个namespace,则共用一个缓存。
mybatis默认情况下没有开启二级缓存,需要手动配置开启,需要两步:1. 在mybatis.xml配置文件中加入<setting name ="cacheEnabled" value="true" />(开启二级缓存)。 2. 在涉及缓存的mapper.xml中声明<cache/>(和select,update等同级)。仅仅这样的话会报异常NotSerializableException(没有序列化)。因为将数据放入内存不需要序列化,放入硬盘需要序列化,所以可知二级缓存是将查询结果放入硬盘(一级查询放入内存)。序列化:内存到硬盘。反序列化:硬盘到内存。所以要把mapper.xml对应的实体类、继承的父类以及关联属性的实体类都实现序列化接口implements Serializable。通过IO写入硬盘也比较消耗性能,因此不能查询一次就存一次,要有特定时机一次性写入硬盘,这个时机就是执行sqlSession的close()方法。如果某个<select>语句需要禁用缓存,只需要<select id="" useCache="false">即可。清理缓存和一级缓存一样,执行commit()操作就会清理缓存,增加删除和修改需要commit就是为了清理缓存,防止查询到的是缓存的数据,不是更新以后的。但是commit不能是查询的session的commit,而是执行更新操作的commit。或者通过<select id="" flushCache="true">来清理缓存。
第三方或者自定义二级缓存:
必须实现org.apache.ibatis.cache.Cache接口。Ehcache已经实现过了,默认实现类是PerpetualCache。整合Ehcache首先需要导入三个jar包:Ehcache-core.jar、mybatis-Ehcache.jar、slf4j-api.jar。然后配置Ehcache.xml(全局配置)。
开启Ehcache缓存mapper.xml文件中:
<!--开启Ehcache缓存并修改该mapper的配置属性-->
<cache type="org.mybatis.caches.ehcache.EhcacheCache">
<property name="maxElememtsInMemory" value="2000"> //为该mapper.xml单独配置参数
</cache>。
约定大于配置:
约定的目标就是省略掉statement,根据约定直接定位出sql语句。
也就是定义一个mapper的接口,让其抽象方法和mapper.xml中的增删查改sql语句对应,应做到如下几点:
1.interface(接口)的全类名要和<mapper namespace="该mapper.xml的全称,不带后缀">中namespace的名称对应。
2.抽象方法的方法名要和 <select id="">中的id对应。
3.抽象方法的返回类型要和resultType的类型对应。
4.抽象方法的参数类型要和parameterType的类型对应。
约定完成后,即可根据接口的方法找到原本mapper.xml中的sql。(动态代理)
SqlSession session = sessionFactory.openSession();
//根据Session对象获取接口,参数和返回的都是接口。(这里StudentMapper是个接口,不是xml文件)
StudentMapper studentMapper = session.getMapper(StudentMapper.class);
//调用接口中的方法,mybatis会动态代理根据约定找到Mapper.xml中的sql执行(不需要接口的实现类)
studentMapper.queryByStuNo(1);
session.close();