MyBatis记错本
1.第一个简单的MyBatis程序
1.personMapper.xml image.png
2.config.xml image.png
3.main方法
2. image.png
default可以选择用下面的哪个数据库连接,可以写多个environment标签
上图的地方可以修改development
3.
POOLED代表使用数据库连接池,UNPOOLED代表不使用数据库连接池,即传统的JDBC方式
4. image.png
一个联网的才能找到的文件,可以下载下来导入,那样不联网也会有提示信息。
5.
6.两种方式的增删改查
1.基础方式的增删改查CRUD
2.mapper动态代理方式的CRUD(MyBatis接口开发)
原则:约定优于配置
7.优化
1.可以将配置信息 单独放入 db.properties文件中,然后再动态引入
db.properties:
k=v
<configuration>
<properties resource="db.properties"/>
引入之后,使用${key}
2.MyBatis全局参数
在conf.xml中设置
<settings>
<setting name="cacheEnabled" value="false" />
<setting name="lazyLoadingEnabled" value="false" />
</settings>
3.别名 conf.xml
a.设置单个别名
b.批量设置别名
<typeAliases>
<!-- 单个别名 (别名 忽略大小写) -->
<!-- <typeAlias type="org.lanqiao.entity.Student" alias="student"/> -->
<!-- 批量定义别名 (别名 忽略大小写),以下会自动将该包中的所有类 批量定义别名: 别名就是类名(不带包名,忽略大小写) -->
<package name="org.lanqiao.entity"/>
</typeAliases>
除了自定义别名外,MyBatis还内置了一些常见类的别名。
4.类型处理器(类型转换器)
1.MyBatis自带一些常见的类型处理器
int - number
2.自定义MyBatis类型处理器
java -数据库(jdbc类型)
示例:
实体类Student : boolean stuSex
true:男
false:女
表student: number stuSex
1:男
0:女
自定义类型转换器(boolean -number)步骤:
a.创建转换器:需要实现TypeHandler接口
通过阅读源码发现,此接口有一个实现类 BaseTypeHandler ,因此 要实现转换器有2种选择:
i.实现接口TypeHandler接口
ii.继承BaseTypeHandler
需要注意的问题: INTEGER
insert into student(stuno,stuname,stuage,graname,stusex) values(#{stuNo},#{stuName},#{stuAge},#{graName} ,#{stuSex ,javaType=boolean ,jdbcType=INTEGER } )
注意#{stuNo} 中存放的是 属性值,需要严格区分大小写。
5.resultMap可以实现2个功能:
1.类型转换
2.属性-字段的映射关系
<select id="queryStudentByStuno" parameterType="int" resultMap="studentMapping" >
select * from student where stuno = #{stuno}
</select>
<resultMap type="student" id="studentMapping">
<!-- 分为主键id 和非主键 result-->
<id property="id" column="stuno" />
<result property="stuName" column="stuname" />
<result property="stuAge" column="stuage" />
<result property="graName" column="graname" />
<result property="stuSex" column="stusex" javaType="boolean" jdbcType="INTEGER"/>
</resultMap>
8.输入参数:parameterType
1.类型为 简单类型(8个基本类型+String)
#{}、${}的区别
a.
#{任意值}
${value} ,其中的标识符只能是value
b.
#{}自动给String类型加上'' (自动类型转换)
${} 原样输出,但是适合于 动态排序(动态字段)
select stuno,stuname,stuage from student where stuname = #{value}
select stuno,stuname,stuage from student where stuname = '${value}'
动态排序:
select stuno,stuname,stuage from student order by ${value} asc
c.#{}可以防止SQL注入
${}不防止
${}、#{}相同之处:
a.都可以 获取对象的值 (嵌套类型对象)
i.获取对象值:
模糊查询,方式一:
select stuno,stuname,stuage from student where stuage= #{stuAge} or stuname like #{stuName}
Student student = new Student();
student.setStuAge(24);
student.setStuName("%w%");
List<Student> students = studentMapper.queryStudentBystuageOrstuName(student) ;//接口的方法->SQL
模糊查询,方式二:
student.setStuName("w");
select stuno,stuname,stuage from student where stuage= #{stuAge} or stuname like '%${stuName}%
ii.嵌套类型对象
通过级联获得
9.输入对象为HashMap:
where stuage= #{stuAge}
用map中key的值 匹配 占位符#{stuAge},如果匹配成功 就用map的value替换占位符
10.mybatis调用存储过程
<select id="queryCountByGradeWithProcedure" statementType="CALLABLE" parameterType="HashMap" >
{
CALL queryCountByGradeWithProcedure(
#{gName,jdbcType=VARCHAR,mode=IN},
#{scount,jdbcType=INTEGER,mode=OUT}
)
}
</select>
其中 通过statementType="CALLABLE"设置SQL的执行方式是存储过程。 存储过程的输入参数gName需要通过HashMap来指定
在使用时,通过hashmap的put方法传入输入参数的值;通过hashmap的Get方法 获取输出参数的值。
要注意Jar问题:ojdbc6.jar不能在 调存储过程时 打回车、tab,但是ojdbc7.jar可以。
如果报错: No enum constant org.apache.ibatis.type.JdbcType.xx,则说明mybatis不支持xx类型,需要查表。
存储过程 无论输入参数是什么值,语法上都需要 用map来传递该值;
只要 是 <transactionManager type="JDBC" />,则增删改都需要手工commit ;
11.输出参数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),则可能是 表的字段 和 类的属性名字写错。
12.动态sql*
两种动态sql方式 where 1=1 where标签方式
<where>会自动处理第一个<if>标签中的 and,但不会处理之后<if>中的and
<foreach>的使用
<foreach>迭代的类型:数组、对象数组、集合、属性(Grade类: List<String> names)
简单类型的数组:
无论编写代码时,传递的是什么参数名(stuNos),在mapper.xml中 必须用array代替该数组
集合:
对象数组:
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.提取相似代码
注:当要引用的sql语句在另一个xml文件中时,调用时refid属性中应该写namespace名.sql语句的id名
13.关联查询
一对一 image.png
一对多 image.png
注意与一对一语法上的区别,比如javaType与·ofType;association与collection
14.日志: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中的参数 和返回结果)
15.延迟加载(懒加载):
一对一、一对多、多对一、多对多
一对多:班级-学生 ,
如果不采用延迟加载 (立即加载),查询时会将 一 和多 都查询,班级、班级中的所有学生。
如果想要 暂时只查询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>
image.png