mybatis相关笔记

Dao层
MyBatis可以简化JDBC操作,实现数据的持久化(存入数据库)

ORM(概念):Object Relational Mapping
对象 《-》 表 之间的映射
MyBatis是ORM的一个实现
ORM使得开发人员像操作对象一样操作数据库表

day01
1、开发mybatis程序步骤
1)、mybatis.jar mysql.jar
2)、表 - 类 相对应
配置mybatis:配置数据库信息和需要加载的映射的文件(conf.xml)
映射文件(xxMapper.xml):增删改查标签

3)、测试类:
	Reader reader = Resources.getResourceAsReader("conf.xml");
	//SqlSessionFactory
	SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
	
	SqlSession session = sessionFactory.openSession();
	//namespace+id
	String statement = "com.java.entity.personMapper.queryPersonById";
	//session.selectOne("需要查询sql的namespace+id","sql的参数值")
	Person person = session.selectOne(statement,1);
	System.out.println(person);

day02

复习第一个MyBatis
1、mybatis.jar mysql.jar
2、conf.xml(数据库配置信息、映射文件)
3、表-类:映射文件 mapper.xml
4、测试



一、基础方式的增删改查CRUD
注意事项:
a、如果使用的事务方式为jdbc,则需要手动提交,即session.commit();(增删改需要提交事务)
b、所有增删改查标签都必须有sql语句,但是sql参数值可选

二、mapper动态代理方式的CRUD(mybatis接口开发):
原则:约定优于配置
硬编码方式:
abc.java
Configuration conf = new Configuration();
conf.setName(“myProject”);
配置方式:
abc.xml
myProject
约定:默认值就是myProject

具体实现的步骤:
	1、基础环境
	2、(不同之处)
		约定的目标:省略掉statement,即根据约定直接定位出sql语句
		a、接口(接口中的方法必须遵循以下约定)
			1、方法名和mapper.xml文件中标签的id值相同 
			2、方法的输入参数和mapper.xml文件中标签的paramterType类型一致
			3、方法的返回值和mapper.xml文件中标签的resultType类型一致
		****除了以上约定,要实现接口中的方法和Mapper.xml中sql标签一一对应,还需要以下1点:
			namespace的值就是接口的全类名(接口和xml文件的映射)
		
		约定过程:
			1、根据接口的全类名定位到mapper.xml文件(namespace值)
			2、根据接口的方法名找到mapp.xml文件中的sql标签
				(方法名=id,输入参数类型=paramterType,返回值类型=resultType)
			当我们调用接口中的方法时,程序能自动定位到某一个Mapper.xml文件中的sql标签
		习惯:将sql映射文件(mapper.xml)和接口放在同一个包中
		执行:
			StudentMapper studentMapper = session.getMapper(StudentMapper.class);
			studentMapper.方法;

		StudentMapper studentMapper = session.getMapper(StudentMapper.class);
		List<Student> students = studentMapper.queryAllStudents();

优化:
	1、可以将配置信息单独放入db.properties文件中,然后再动态引入(设置全局参数)
	db.properties:key=value
	<configuration>
		<properties resource="db.properties"/>
	使用方式:${key}=value
	2、MyBatis全局参数配置
	在conf.xml文件中设置
	<settings>
		<setting name="cacheEnabled" value="false"/><!-- 关闭缓存  -->
	</settings>
	3、别名
	conf.xml中设置(大小写不敏感)
	a、设置单个别名
	<typeAliases>
		<typeAlias type="com.java.entity.Student" alias="student"/>
	</typeAliases>
	b、批量设置别名
	会自动将该包中的所有类批量定义别名:别名就是类名
	<typeAliases>
		<pakage name="com.java.entity" />
	</typeAliases>

三、类型处理器(类型转换器)
1、MyBatis自带一些常见的类型处理器

2、自定义mybatis类型处理器
	java - 数据库(jdbc类型)

自定义类型转换器(boolean - number)步骤
	a、创建转换器
		i、实现TypeHandler接口
		此接口有一个实现类BaseTypeHandler
		ii、继承实现类BaseTypeHandler
	b、配置conf.xml

day03
1、输入参数:parameterType
i、类型为简单类型(8个基本类型+String)
a、#{任意值}
${value}
b、二者区别:
#{任意值}:自动给String类型加上单引号(自动类型转换)
${value}:原样输出,但是适用于动态排序(动态字段)
select * from student order by KaTeX parse error: Expected 'EOF', got '#' at position 16: {value} asc #̲{}可以防止SQL注入 c…{}两者相同之处:
都可以获取对象的值(嵌套对象)
模糊查询
select * from student where stuname like ‘%${stuName}%’

ii、类型为对象类型
	#{属性名}
	${属性名}

iii、嵌套类型对象

2、mybatis调用存储过程
mapper.xml->mapper接口(dao接口)->测试方法
1)、查询某个年级的学生总数
输入:年级
输出:该年级的学生总数
创建存储过程
CREATE PROCEDURE queryCountByGradeWithProcedure(in gName varchar(20),out scount INT)
BEGIN
SELECT count(*) INTO scount FROM student WHERE graname = gname;
END

<!-- 通过调用[存储过程]实现查询 statementType="CALLABLE"
存储过程的输入参数,在mybatis用Map来传递(HashMap) -->
<select id="queryCountByGradeWithProcedure" statementType="CALLABLE"  parameterType="HashMap">
	{
	CALL queryCountByGradeWithProcedure(
		#{gName,jdbcType=VARCHAR,mode=IN},
		#{sCount,jdbcType=INTEGER,mode=OUT}
	)
	}
</select>
要点:
	1、statementType="CALLABLE"
	2、parameterType="HashMap"
	3、Object count = params.get("sCount");//获取输出参数
	4、注意jar问题
	5、存储过程无返回值
2)、根据学号删除学生
CREATE PROCEDURE deleteStudentByStunoWithProcedure(in sno int)
BEGIN
		DELETE FROM student WHERE stuno = sno;
END

day04
resultType
resultMap:当数据库字段和实体类的属性:类型、名字不同时
注意:当属性名和字段名不一致时,还可以使用resultType和HashMap
1、输出参数resultType
i、简单类型(8个基本+String)
ii、对象类型
iii、输出参数为实体对象类型的集合
映射文件中 resultType依然写集合的元素类型
接口中 为实体对象类型的集合
vi、输出类型为hashmap
–hashmap本身是一个集合,可以存放多个元素


select stuno “no”,stuname “name” from student

2、输出参数resultMap
当实体类属性名和数据库字段名不一致时
i、

	<resultMap type="student" id="studentsexResult">
		<!-- 分为主键和非主键 -->
		<id property="stuNo" column="id"/>
		<result property="stuName" column="name"/>
	</resultMap>
	ii、为数据库字段id和name设置别名“stuNo”和“stuName”
	<select id="queryStudentOutByHashMap" resultType="Student">
		select id "stuNo",name "stuName" from student
	</select>

3、动语态sql
1)、where标签
select stuno,stuname,stuage from student

		<where>
			<!-- <if test="student有stuname属性且不为null时"> -->
			<if test="stuName != null and stuName!='' ">
				and stuname = #{stuName}
			</if>
			<if test="stuAge != null and stuAge!=0 ">
				and stuage = #{stuAge}
			</if>
		</where>
	//where会自动处理第一个<if>中的and,但不会处理之后的and
2)、foreach标签
	迭代的类型:数组、集合、对象数组、属性(grade类:List<Integer> IDS)
	open()
	item:迭代标签
	close()
	separator=","定义每个元素之间的分隔符号
i、类属性的迭代(Grade类的属性:stuNos)
<select id="queryStudentsWithNosInAge" parameterType="com.java.entity.Grade" resultType="student">
			select * from student 
			<where>
				<if test="stuNos != null and stuNos.size>0">
					<foreach collection="stuNos" open=" and stuage in(" close=")" item="name" separator=","><!-- 通过foreach遍历集合 -->
						#{name}
					</foreach>
				</if>
			</where>
		</select>
ii、简单数组类型的迭代
	迭代参数固定为array
	collection="array"
	无论编写代码时传递的是什么参数名(stuage),在mapper.xml中必须用array代替数组
iii、集合类型的迭代
	无论编写代码时传递的是什么参数名(stuage),在mapper.xml中必须用list代替数组
vi、对象数组
	无论编写代码时传递的是什么参数名(stuage),在mapper.xml中必须用Object[]代替数组

3)、相同的代码段(sql片段)
	java:方法
	数据库:存储过程、存储函数
	mybatis:sql片段
<select id="queryStudentsWithList" parameterType="List" resultType="student">
			select * from student 
			<include refid="queryStudentList"></include>
		</select>
		<!-- 提取相同的sql语句 -->
		<sql id="queryStudentList">
			<where>
				<if test="list != null and list.size>0">
					<foreach collection="list" open=" and stuage in(" close=")" item="name" separator=","><!-- 通过foreach遍历集合 -->
						#{name}
					</foreach>
				</if>
			</where>
		</sql>

4、关联查询
1)、主键和外键的作用
1.主键是能确定一条记录的唯一标识,比如,一条记录包括身份正号,姓名,年龄。

	身份证号是唯一能确定你这个人的,其他都可能有重复,所以,身份证号是主键。 
	2.外键用于与另一张表的关联。是能确定另一张表记录的字段,用于保持数据的一致性。

	比如,A表中的一个字段,是B表的主键,那他就可以是A表的外键。
2)、一对一
	a、业务扩展类
		核心:用resultType指定的类的属性包含多表查询的所有字段
	b、resultMap
		i、通过属性成员将2个类建立联系
		ii、
<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="com.java.entity.StudentCard">
					<id property="cardId" column="cardId"/>
					<result property="cardInfo" column="cardInfo"/>
				</association>
			</resultMap>
			
			<select id="queryStudentByNowithOO2" resultMap="student_card_map" parameterType="int">
				select s.*,c.* from student s inner join studentcard c on s.cardid = c.cardid
				where s.stuno = #{stuNo}
			</select>
	*一对一:association  javaType
	一对多:collection  ofType
3)、一对多
<!-- 一对多关联查询 -->
		<select id="queryClassAndStudents" resultMap="class_student_map" parameterType="int">
			select c.*,s.* from student s
			inner join studentclass c
			on c.classid=s.classid
			where c.classid = #{classid}
		</select>
		<resultMap type="com.java.entity.StudentClass" id="class_student_map">
			<id property="classId" column="classId"/>
			<result property="className" column="className"/>
			<!-- 配置成员属性学生,一对多;ofType -->
			<collection property="students" ofType="Student">
				<id property="stuNo" column="stuNo"/>
				<result property="stuName" column="stuName"/>
				<result property="stuAge" column="stuAge"/>
				<result property="graName" column="graName"/>
				<association property="address" javaType="com.java.entity.Address">
					<id property="homeAddress" column="homeAddress"/>
					<result property="schoolAddress" column="schoolAddress"/>
				</association>
				<association property="card" javaType="com.java.entity.StudentCard">
					<id property="cardId" column="cardId"/>
					<result property="cardInfo" column="cardInfo"/><!-- 未关联 -->
				</association>
			</collection>
		</resultMap>

day05

1、日志
a、Log4j:(mybatis.zip的lib中包含该jar)
log4j.jar

b、在conf.xml配置文件中指定日志
	<settings>
		<!-- 开启日志,并指定使用的具体日志 -->
		<setting name="logImol" 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中的参数和返回结果)

2、延迟加载
//将原查询sql语句分成两个子查询
延迟加载需要在另一个mapper中写
a、一对一
mybatis中使用延迟加载需要先在conf.xml中配置






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

<select id="queryStudentByNowithOOLazyLoad" resultMap="student_card_LazyLoad_map" parameterType="int">
	<!-- 先查询学生 -->
	select * from student where cardId = #{cardid}
</select>
<!-- 类-表的对应关系 -->
<resultMap type="student" id="student_card_LazyLoad_map">
	<id property="stuNo" column="stuNo"/><!-- 主键 -->
	<result property="stuName" column="stuName"/><!-- 非主键 -->
	<result property="stuAge" column="stuage"/>
	<result property="graName" column="graName"/>
	<!-- 一对一时,对象成员使用association映射;javaType指定该属性的类型 
		采用延迟加载:查询学生时,并不立即加载学生证信息
	-->
	<!-- 学生证 通过select在需要的时候再查学生证
	查询学生证的sql是通过select属性指定,并且通过column指定外键-->                                                                                 
<association property="card" javaType="com.java.entity.StudentCard" 
		select="com.java.mapper.StudentCardMapper.queryCardById" column="cardId"><!-- column:外键字段 -->
		</association>
	</resultMap>

	<mapper namespace="com.java.mapper.StudentCardMapper"><!-- namespace:映射文件的路径 -->
		<!-- 查询学生证信息 -->
		<select id="queryCardById" parameterType="int" resultType="com.java.entity.StudentCard">
			<!-- 查询学生对应的学生证 -->
			select * from studentcard where cardid = #{cardId}
		</select>
<!-- 根据cardid查询学生证的sql: com.java.mapper.StudentCardMapper.queryCardById-->
</mapper>
b、一对多
	和一对一的延迟加载配置方法相同
	班级mapper.xml
	
	学生mapper.xml

总结:延迟加载的步骤:先查班级,按需求查学生
1、开启延迟加载conf.xml配置setting
2、配置mapper.xml
学生mapper.xml

<select id="queryStudentByNowithOOLazyLoad" resultMap="student_card_LazyLoad_map" parameterType="int">
				<!-- 先查询学生 -->
				select * from student where cardid = #{cardid}
			</select>
	学生证mapper.xml
<select id="queryCardById" parameterType="int" resultType="com.java.entity.StudentCard">
				<!-- 查询学生对应的学生证 -->
				select * from studentcard where cardid = #{cardId}
			</select>

day06
1、 查询缓存
i、一级缓存 同一个SqlSession对象
mybatis默认开启一级缓存(如果用相同的sqlsession对象查询相同的数据,则只会在第一次
查询时向数据库发送sql语句,并将查询的结果放入到sqlsession中[作为缓存],后续再次查询该同样的
对象时,则直接从缓存中查询该对象即可[即省略了数据库的访问])
session. commit()会清除缓存
ii、二级缓存
session.close();//进行二级缓存的时刻
a、mybatis自带的二级缓存(默认关闭):【同一个namespace】生成的mapper对象
回顾:namespace的值就是接口的全类名(包名.类名)
开启二级缓存:
1)、conf.xml




2)、在具体的mapper.xml中声明开启


异常java.io.NotSerializableException
mybatis的二级缓存是将对象从内存放入硬盘(序列化)
3)、准备缓存的对象,必须实现了序列化接口
序列化Student类的级联属性、父类

		触发将对象写入二级缓存的时机:session.close();//进行二级缓存的时刻
		Cache Hit Ratio [com.java.mapper.StudentMapper]: 0(第一次查询命中率)
		Cache Hit Ratio [com.java.mapper.StudentMapper]: 0.5(第二次查询命中率)
		Cache Hit Ratio [com.java.mapper.StudentMapper]: 0.75(第四次查询命中率)
	
		4)、禁用:在select标签中useCache=“false”
	
		5)、清理:与清理一级缓存的方法相同
			session.commit();(一般执行增删改时会清理掉缓存[防止脏数据的产生])
			commit会清理一级和二级缓存;但是清理二级缓存时,不能是查询自身的commit
	
			清理缓存的第二种方式
			在select标签中flushCache="true"
	
	b、第三方提供的二级缓存
		ehcache、memcache
		要想整合三方提供的二级缓存(或自定义二级缓存)必须实现Cache接口,该接口的
		默认实现类PerpetualCache
		
		整合ehcache二级缓存:
		
		1)、jar包
		Ehcache-core.jar
		mybatis-ehcache.jar
		slf4j-api.jar
		2)、编写ehcache配置文件EhCache.xml;
		3)、开启ehcache二级缓存
		<cache type="org.mybatis.caches.ehcache.EhcacheCache">
			<!-- 通过property覆盖默认值 -->
			<property name="" value=""/>
		</cache>

2、逆向工程(不实用)
表、类、接口、mapper.xml四者密切相关,因此当知道一个的时候,其他三个应该可以自动生成

表-》其他三个

实现步骤:
a、jar包
	mybatis-generator-core.jar
b、逆向工程的配置文件generator.xml

c、执行test类
	List<String> warnings = new ArrayList<String>();
	ConfigurationParser cp = new ConfigurationParser(warnings);
	File file = new File("src/generator.xml");//配置文件
	Configuration config = cp.parseConfiguration(file);
	DefaultShellCallback callback = new DefaultShellCallback(true);
	//逆向工程的核心类
	MyBatisGenerator generator= new MyBatisGenerator(config,callback,warnings);
	generator.generate(null);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值