Mybaits基础笔记

280 阅读9分钟

selectKey用法! blog.csdn.net/xu191665942…

开发mybatis程序从步骤:

一.配置mybatis
conf.xml:配置数据库信息 和 需要加载的映射文件
表 - 类
映射文件xxMapper.xml :增删改查标签 测试类:

session.selectOne("需要查询的SQL的namespace.id","SQL的参数值");

b.#{}自动给String类型加上'' (自动类型转换)

${} 原样输出,但是适合于 动态排序(动态字段) 动态排序:

select stuno,stuname,stuage  from student  order by ${value} asc

输入对象为HashMap: where stuage= #{stuAge}

用map中key的值 匹配 占位符#{stuAge},如果匹配成功 就用map的value替换占位符

如果报错: No enum constant org.apache.ibatis.type.JdbcType.xx,则说明mybatis不支持xx类型,需要查表。

存储过程 无论输入参数是什么值,语法上都需要 用map来传递该值;

只要 是 <transactionManager type="JDBC" />,则增删改都需要手工commit ;

如果输入参数 :是简单类型(8个基本类型+String) 是可以使用任何占位符,#{xxxx} 如果是对象类型,则必须是对象的属性 #{属性名}

输出参数: 如果返回值类型是一个 对象(如Student),则无论返回一个、还是多个, 再resultType都写成org.lanqiao.entity.Student 即 resultType="org.lanqiao.entity.Student"

二、mapper动态代理方式的crud (MyBatis接口开发):
接口中的方法必须遵循以下约定

  1. 方法名和mapper.xml文件中标签的id值相同

  2. 方法的 输入参数 和mapper.xml文件中标签的 parameterType类型一致 (如果mapper.xml的标签中没有 parameterType,则说明方法没有输入参数)

  3. 方法的返回值 和mapper.xml文件中标签的 resultType类型一致 (无论查询结果是一个 还是多个(student、List),在mapper.xml标签中的resultType中只写 一个(Student);如果没有resultType,则说明方法的返回值为void)

除了以上约定,要实现 接口中的方法 和 Mapper.xml中SQL标签一一对应,还需要以下1点: namespace的值 ,就是 接口的全类名( 接口 - mapper.xml 一一对应)

匹配的过程:(约定的过程) 1.根据 接口名 找到 mapper.xml文件(根据的是namespace=接口全类名) 2.根据 接口的方法名 找到 mapper.xml文件中的SQL标签 (方法名=SQL标签Id值) 执行:

		StudentMapper studentMapper = session.getMapper(StudentMapper.class) ;
		studentMapper.方法();

通过session对象获取接口(session.getMapper(接口.class);),再调用该接口中的方法,程序会自动执行该方法对应的SQL。

.可以将配置信息 单独放入 db.properties文件中,然后再动态引入

批量设置别名

	<typeAliases>
		<!-- 单个别名 (别名 忽略大小写) -->
		<!-- <typeAlias type="org.lanqiao.entity.Student" alias="student"/> -->
		<!--  批量定义别名  (别名 忽略大小写),以下会自动将该包中的所有类 批量定义别名: 别名就是类名(不带包名,忽略大小写)   -->
		<package name="org.lanqiao.entity"/>
	</typeAliases>
类型处理器(类型转换器)

1.MyBatis自带一些常见的类型处理器 int - number

2.自定义MyBatis类型处理器

java -数据库(jdbc类型)

示例: 实体类Student : boolean stuSex true:男 false:女

表student: number stuSex 1:男 0:女 自定义类型转换器(boolean -number)步骤: a.创建转换器:需要实现TypeHandler接口

resultMap可以实现2个功能: 1.类型转换 2.属性-字段的映射关系

1.查询缓存 一级缓存 :同一个SqlSession对象 MyBatis默认开启一级缓存,如果用同样的SqlSession对象查询相同的数据, 则只会在第一次 查询时 向数据库发送SQL语句,并将查询的结果 放入到SQLSESSION中(作为缓存在); 后续再次查询该同样的对象时, 则直接从缓存中查询该对象即可(即省略了数据库的访问)

二级缓存
	MyBatis默认情况没有开启二级缓存,需要手工打开。
	a.conf.xml
	<!-- 开启二级缓存 -->
		<setting name="cacheEnabled" value="true"/>
	b.在具体的mapper.xml中声明开启(studentMapper.xml中)
			<mapper namespace="org.lanqiao.mapper.StudentMapper">

			<!-- 声明次namespace开启二级缓存 -->
			<cache/>
		根据异常提示:NotSerializableException可知,MyBatis的二级缓存 是将对象 放入硬盘文件中	
			序列化:内存->硬盘
			反序列化:硬盘->内存
	准备缓存的对象,必须实现了序列化接口 (如果开启的缓存Namespace="org.lanqiao.mapper.StudentMapper"),可知序列化对象为Student,因此需要将Student序列化 (序列化Student类,以及Student的级联属性、和父类)

	触发将对象写入二级缓存的时机:SqlSession对象的close()方法。


	Mybatis自带二级缓存:【同一个namespace】生成的mapper对象
	禁用 :select标签中useCache="false"
	commit会清理一级和二级缓存;但是 清理二级缓存时,不能是查询自身的commit;
      b. 在select标签中 增加属性 flushCache="true"

      要想整合三方提供的二级缓存 (或者自定义二级缓存),必须实现org.apache.ibatis.cache.Cache接口,该接口的默认实现类是PerpetualCache

输出参数resultType 1.简单类型(8个基本+String) 2.输出参数为实体对象类型 3.输出参数为实体对象类型的集合 :虽然输出类型为集合,但是resultType依然写 集合的元素类型(resyltType="Student") 4.输出参数类型为HashMap --HashMap本身是一个集合,可以存放多个元素, 但是根据提示发现 返回值为HashMap时 ,查询的结果只能是1个学生(no,name); -->结论:一个HashMap 对应一个学生的多个元素(多个属性) 【一个map,一个学生】

二维数组

{
	{1,zs,23,xa},    -一个HashMap对象
	{2,ls,24,bj}, 
	{3,ww,25,tj}
}

resultType resultMap:实体类的属性、数据表的字段: 类型、名字不同时(stuno,id) 注意:当属性名 和字段名 不一致时,除了使用resultMap以外,还可以使用resultType+HashMap:

a.resultMap

	<resultMap type="student" id="queryStudentByIdMap">
			<!-- 指定类中的属性 和 表中的字段 对应关系 -->
			<id property="stuNo"  column="id" />
			<result property="stuName" column="name" />
	</resultMap>
	

b.resultType+HashMap select 表的字段名 "类的属性名" from... 来制定字段名 和属性名的对应关系

	<select id="queryStudentByIdWithHashMap" 	 parameterType="int"	resultType="student" >
		select id "stuNo",name "stuName" from student where id = #{id}
	</select>

注意: 如果如果10个字段,但发现 某一个字段结果始终为默认值(0,0.0,null),则可能是 表的字段 和 类的属性名字写错。

//查询全部

String statement = "select stuno,stuname from student";

//根据年龄查询学生

String statement = "select stuno,stuname from student where stuage = #{stuage}"; 

//根据姓名和年龄查询学生

String statement = "select stuno,stuname from student where stuage = #{stuage} and stuage = #{stuage} "; 

select stuno,stuname from student where  stuname = #{stuName}and  stuage = #{stuAge}





select stuno,stuname,stuage from student <where> and stuname = #{stuName}  and  stuage = #{stuAge}

会自动处理第一个标签中的 and,但不会处理之后中的and

查询学号为1、2、53的学生信息

ids = {1,2,53};

select stuno,stuname from student  where stuno in(1,2,53) 

迭代的类型:数组、对象数组、集合、属性(Grade类: List ids)

属性(Grade类: List ids)


select * from student 
open:
select * from student and  stuno in (
item:
select * from student and  stuno in (1253
close:
select * from student and  stuno in (1,2,53)

简单类型的数组: 无论编写代码时,传递的是什么参数名(stuNos),在mapper.xml中 必须用array代替该数组

集合: 无论编写代码时,传递的是什么参数名(stuNos),在mapper.xml中 必须用list代替该数组

对象数组: Student[] students = {student0,student1,student2} 每个studentx包含一个学号属性 注意的几点:

	parameterType="Object[]" 
	 	<foreach collection="array" open=" and  stuno in (" close=")" 
	  		 		item="student" separator=",">   
	  		 		#{student.stuNo}
	  	</foreach>


SQL片段: java:方法 数据库:存储过程、存储函数 Mybatis :SQL片段

a.提取相似代码 b.引用

关联查询: 一对一: a.业务扩展类 核心:用resultType指定类的属性 包含 多表查询的所有字段

b.resultMap i.通过 属性成员 将2个类建立起联系 2.

<resultMap type="student" id="student_card_map">
			<!-- 学生的信息 -->
			<id  property="stuNo" column="stuNo"/>
			<result property="stuName" column="stuName" />
			<result property="stuAge" column="stuAge" />
			<!-- 一对一时,对象成员使用 association映射;javaType指定该属性的类型-->
			<association property="card" javaType="StudentCard" >
					<id property="cardId" column="cardId"/>
					<result property="cardInfo" column="cardInfo"/>
			</association>
			
	</resultMap>

一对一:association 一对多:collection

一对多: 表:student studentclass (关联:classid) 类:student studentClass (关联:List students )

select  c.*,s.* from student s
		inner join studentclass c 
		on c.classid = s.classid
		where c.classid = 1;

一对多

(MyBatis:多对一,多对多的本质就是 一对多的变化)

日志:Log4j

a.Log4j: log4j.jar (mybatis.zip中lib中包含此jar) b.开启日志,conf.xml

	<settings>
		<!-- 开启日志,并指定使用的具体日志 -->
		<setting name="logImpl" value="LOG4J"/>
	
	</settings>

如果不指定,Mybatis就会根据以下顺序 寻找日志 SLF4J →Apache Commons Logging →Log4j 2 → Log4j →JDK logging

c.编写配置日志输出文件

log4j.properties,内容
log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

日志级别: DEBUG<INFO<WARN<ERROR 如果设置为info,则只显示 info及以上级别的信息; 建议:在开发时设置debug,在运行时设置为info或以上。

可以通过日志信息,相信的阅读mybatis执行情况( 观察mybatis实际执行sql语句 以及SQL中的参数 和返回结果)

延迟加载(懒加载): 一对一、一对多、多对一、多对多 一对多:班级-学生 , 如果不采用延迟加载 (立即加载),查询时会将 一 和多 都查询,班级、班级中的所有学生。 如果想要 暂时只查询1的一方, 而多的一方 先不查询 而是在需要的时候再去查询 -->延迟加载

一对一:学生、学生证

mybatis中使用延迟加载,需要先配置:

	<settings>
		<!-- 开启延迟加载 -->
		<setting name="lazyLoadingEnabled" value="true"/>
		
		<!-- 关闭立即加载 -->
		<setting name="aggressiveLazyLoading" value="false"/>
	</settings>

如果增加了mapper.xml ,要修改conf.xml配置文件(将新增的mapper.xml加载进去)

通过debug可以发现, 如果程序只需要学生,则只向数据库发送了查询学生的SQL; 当我们后续 需要用到学生证的时候,再第二次发送 查询学生证的SQL。

一对多:和一对一的延迟加载配置方法相同

延迟加载的步骤:先查班级,按需查询学生 1.开启延迟加载conf.xml配置settings 2.配置mapper.xml 写2个Mapper: 班级mapper.xml

		<select id="queryClassAndStudents"   resultMap="class_student_lazyLoad_map">
		
			select  c.* from studentclass c
		</select>		

	<resultMap type="studentClass" id="class_student_lazyLoad_map">
			<!-- 因为 type的主类是班级,因此先配置班级的信息-->
			<id  property="classId" column="classId"/>
			<result  property="className" column="className"/>
			<!-- 配置成员属性学生,一对多;属性类型:javaType,属性的元素类型ofType -->
			<!-- 2222222再查班级对应的学生 -->
			<collection property="students" ofType="student" select="org.lanqiao.mapper.StudentMapper.queryStudentsByClassId" column="classid">

			</collection>
	</resultMap>

即查询 学生的sql是通过 select属性指定,并且通过column指定外键 学生mapper.xml

	<!-- 一对多,延迟加载需要的: 查询班级中的所有学生 -->
	<select id="queryStudentsByClassId" parameterType="int" resultType="student">
	select * from student where classId = #{classId}
	</select>