MyBatis笔记
输入参数:parameterType
- 类型为 简单类型(8个基本类型+String)
- #{} ${}
#{任意值}
${value},其中的标识符只能是value
- #{}自动给String类型加上’’(自动类型转换)
${} 原样输出,但是适合于动态排序(动态字段)
Select stno,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
- #{}可以防止SQL输入
${}不可以
- ${} #{} 相同之处:
- 都可以 获取对象的值(嵌套类型对象)
- 获取对象值:
模糊查询,方式一
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> studentList= mapper.queryStudent Like(Student);
模糊查询,方式二
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> studentList= mapper.queryStudent Like(Student);
j. 嵌套类型对象
2.对象类型
#{属性名}
${属性名}
输入对象为HashMap:
Where stuage=#{stuAge}
用map中key的值匹配 占位符#{stuAge},如果匹配成功就用map的value替换占位符
输入对象为HashMap:
Where stuage=#{stuAge}
用map中key的值匹配 占位符#{stuAge},如果匹配成功就用map的value替换占位符
Mybatis调用存储过程
- 查询某个年级的学生总数
<select id="queryCountByAge" statementType="CALLABLE" resultType="int">
{
CALL queryCountByAge(
#{@age,jdbcType=INTEGER,mode=IN},
#{@count,jdbcType=INTEGER,mode=OUT}
)
}
</select>
- 根据学号删除学生
<delete id="deletePersonById" statementType="CALLABLE" parameterType="HashMap" >
{
CALL deletePersonById(
#{@id,jdbcType=INTEGER,mode=IN}
)
}
</delete>
其中通过 statementType=”CALLABLE”设置SQL的执行方式是存储过程。存储过程的输入参数gName需要通过HashMap传值,在使用时,通过hashmap的put方法传入输入参数的值;通过hashmap的Get方法获取输出参数的值。要注意Jar问题:ojdbc6.jar不能l在调用存储过程市打回车、tab,但是ojdbc7.jar可以。
如果报错:No enum constant org.apache.ibatis.type.JdbcType.xx,则说明mybatis不支持**类型,需要查存储过程无论输入参数是什么值,语法上都需要用map来传递改值;只要是<transactionManager type=”JDBC”/>,则增删改都需要commit
mapper.xml ->mapper接口-》测试方法
输出参数resultType
- 简单类型(8个基本+String)
- 输出参数未实体对象类型
- 输出参数未实体对象类型集合:虽然输出类型为集合,但ResultType依然写集合的元素类型
- 输出参数类型为HashMap
---HashMap本身是一个集合,可以存放多个元素,但是根据提示发现 返回值为HashMap时,查询结果只能是一个学生
结论是一个HashMap对应一个学生的多个元素
resultType
resultMap:实体类的属性、数据表的字段:类型、名字不同时(stuno,id)
注意:当属姓名和字段名不一致时,除了使用resultMap以外,还可以使用ResultType+HashMap:
- resultMap
- resultType+HashMap
注意:如果10个字段,但发现某一个字段结果始终为默认值(0,0.0,null)则可能是表的字段和类的属性名字写错
//查询全部学生
String statement=”select stno,stuname from student”;
<where>会自动处理第一个<if>标签中的and,但不会处理之后的<if>中的and
<foreach>
查询学号为1、2、53的学生信息
Ids={1,2,53};
Select stuno,stuname from student where stuno in(1,2, 53)
<foreach>迭代的类型:数组、集合、属性(Grade类:List<Integer> ids)、对象数组
简单类型数组
无论编写代码时,传递的是什么参数名,在mapper.xml中,必须用array代替数组。
集合:
无论编写代码时,传递的是什么参数名(stuNos),在mapper.xml中,必须用list代替该数组。
对象数组:
Student[] students={student0,student1,student2}每个student包含一个学号属性。
注意几点:
parameterType=“Object[]”
SQL片段:
Java:方法
数据库:存储过程、存储函数
Mybatis:SQL片段
- 提取相似代码
- 引用
如果SQL片段和引用处不在同一个文件中,则需要在refid引用时加上namespace
关联查询
一对一:
- 业务扩展类
核心:用resultType指定类的属性 包含 多表查询的所有字段
- resultMap
一对一 association
一对多 collection(多对多,多对一本质上一对多的变化)
- 通过 属性成员将2个类建立起联系
日志:Log4j
SLF4J—》Apache Commons Logging->Log4j 2 ->Log4j ->JDK logging
- Log4j: log4j.jar
- 开启日志,conf.xml
- 编写配置日志输出文件
Log4j.properties
日志级别:DEBUG<INFO<WARN<ERROR
如果设置为info,则只显示info 及以上级别的信息:
建议:在开发时设置debug,在运行时设置为info或以上。
可以通过日志信息,详细的而阅读mybatis执行情况(观察mybatis实际执行sql的语句,以及sql中的参数和返回结果)
延迟加载:
一对一、一对多、多对一、多对多
一对多:班级-学生
如果不采用延迟加载,(立即加载)查询时会将 一和多都查询,班级、班级中的所有学生
如果想要 暂时只查询1的一方,而多的一方先不查询 而是在需要的时候再去查询—》
使用延迟加载的方法
1.在config.xml配置
<settings>
<setting name="logImpl" value="LOG4J"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
如果增加了mapper.xml,需要修改config.xml配置文件(将新增的mapper.xml加载进去)
- 在mapping.xml
<select id="queryPersonCard_lazy" parameterType="int" resultMap="person_card_lazyload_map">
select * from Person
</select>
<resultMap id="person_card_lazyload_map" type="Person">
<id property="id" column="id"/>
<result property="pName" column="pName"/>
<result property="age" column="age"/>
<association property="card" javaType="PersonCard" select="com.lifen.mapper.personCardMapper.queryCardById" column="cardid">
</association>
</resultMap>
增加mapping.xml文件
<select id="queryCardById" parameterType="int" resultType="PersonCard">
select * from personCard where cardid=#{cardid}
</select>
- 查询缓存
一级缓存:同一个SQLSession对象
Mybatis 默认开启一级缓存,如果用同样的SqlSession对象查询相同的数据,则只会在第一次查询时向数据库发送SQL语句,并将查询的结果放入到SQLSession中(作为缓存),后续在此查询该同样的对象时,则直接从缓存中查询改对象即可(即省略了数据库的访问)
二级缓存
MyBatis默认没有开启二级缓存,需要手工打开
- config.xml
- 在具体的mapper.xml中声明开启(studentMapper.xml中)
<mapper namespace=”org.langqiao.mapper.StudentMapper”>
<!—声明namespace 开启二级缓存->
<cache/>
根据异常提示:NotSerializableException 可知,MyBatis的二级缓存是对象放入磁盘序列化
序列化:内存—》硬盘
反序列化:硬盘--》内存
准备缓存的对象必须实现序列化
MyBatis自带二级缓存:同一个namespace 生成的mapper对象,则他们共享缓存。
只要产生的XXXMapper对象来自于同一个namespace,则此对象共享同一个缓存。
禁用二级缓存:select标签中useCache="false"
清理:a. commit()
在二级缓存里,不能是自身的缓存
b.在select标签中 增加属性flushCache=”true”
命中率 zs:0%
三方提供的二级缓存:
ehcache、memcache
a.下载jar包
Ehcache-core.jar
Mybatist-Ehcache.jar
Slf4j-api.jar
b.编写ehcache配置文件Ehcache.xml
c.开启EhCache缓存 <cache type=”org.mybatis.caches.ehcache.EhcaheCache”>
<perperty name=”” value=”’/>
</cache>
- 逆向工程
表、类、接口、mapper.xml四者密切相关,因此当知道一个的时候,其他三个应该可以自动生成。
表----》其他三个
实现步骤:
A、mybatis-generator-core.jar、mybatis.jar 、 ojdbc.jar
B、逆向工程的配置文件generator.xml
C、测试类执行
数据库的环境切换
a. 切换environment
b.配置数据库支持类Provider别名
<databaseIdProvider type="DB_VENDOR">
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="oracle"/>
<property name="SQL Server" value="sqlserver"/>
</databaseIdProvider>
c.写不同数据库的SQL语句
d.在mapper.xml中通过databaseId指定别名
2.注解方式
推荐使用xml
A.将sql语句写在接口的方法上@Select(“”);
B.将借口的全类名写入<mapper>,让mybatis知道sql语句
此时是存储在接口中
注解/xml都支持批量引入<package name=”com.yuanqun.mapper”/>
3.增删改的返回值问题
返回值可以是void、Integer、Long、Boolean 如何操作:只需要再接口中 修改返回值即可
4.事务提交
手动提交:
sessionFactory.openSession();
session.commit();
自动提交:每个dml语句 自动提交
sessionFactory.openSession(true);
5.自增问题
Mysql支持自增
在mapper.xml标签里增加 userGeneratedKeys=”true” keyProperty=”stuNo”就可以获取回写的自增长id值
Oracle默认不支持:通过序列模拟自增
Create sequence myseq increment by 1 start with1;
序列自带两个属性
Nextval:当前序列的下一个值
Currval:序列当前的值
Insert into student(myseq.nextval(),’zs’,23,’al’);
<selectKey keyProperty=”stuNo” resultType=”Integer” order=”before”>
Select myseq.nextval from dual
</selectKey>
Insert into student(stuno,stuName,stuAge,graName)
Value(#{stuNo},#{stuName},#{stuAge},#{graName})
<selectKey keyProperty=”stuNo” resultType=”Integer” order=”after”>
Select myseq.currval from dual
</selectKey>
Insert into student(stuno,stuName,stuAge,graName)
Value(myseq.nextval,#{stuName},#{stuAge},#{graName})
6.参数问题
目前是将多个对象封装在一个javabean对象,然后使用该对象传值。
a.传入多个参数时,不用再Mapper.xml中编写parameterType
只能用 arg0,arg1……或者 param1,param2…..
b.命名参数
可以在接口中通过Param(“”)指定sql中参数的名字
c.综合使用
Integer addStudent(@Param(“stuNo”) Interger stuNo,@Param(“stu”)Student student)
<insert id="insert" databaseId="mysql" >
insert into person ( id,pName, age,
sex, homeAddress, workAddress,
cardid)
values (#{id} ,#{per.pname}, #{per.age},
#{per.sex}, #{per.homeaddress}, #{per.workaddress},
#{per.cardid})
</insert>
7.增加 null
Oracle:如果输入的参数是null,则提示输入Other而不是null
Mysql:如果插入的字段是Null,可以正常执行(没有约束)
原因:
各个数据库在mybatis中对各种数据库类型的默认值不一致。
Mybatis中,jdbcTypeForNull(如果是null),则默认值OTHER。Other来说 MySQL能够处理(NULL),但Oracle不行。
解决
Oracle:null->OTHER,需要手工告诉Oracle: other-》null
a. 当某个数据类型Oracle·无法处理时候,,告诉它用默认值null
<insert id="insert" databaseId="oracle" >
insert into person ( id,pName, age,
sex, homeAddress, workAddress,
cardid)
values (#{id} ,#{per.pname,jdbcType=NULL}, #{per.age},
#{per.sex}, #{per.homeaddress}, #{per.workaddress},
#{per.cardid})
</insert>
b.配置mybatis全局配置文件conf.xml
<setting name="jdbcTypeForNull" value="NULL"/>
8.返回值为HashMap的情况
<select id="selectByPrimaryKeyHashMap" parameterType="java.lang.Integer" resultType="HashMap">
select stuNo, stuName, stuAge, classId
from student
where stuNo = #{stuno,jdbcType=INTEGER}
</select>
@MapKey("stuNo")
HashMap<String,Student> selectAllHashMap();
9.ResultMap 字段和属性名的对应关系
10.鉴别器和别名的问题
在resultMap中 还可以使用鉴别器:对相同sql 中不同字段值进行判断,从而进行不同处理
<discriminator javaType="Integer" column="stuAge">
<case value="20" resultType="com.lifen.entity.Student">
<result column="nickName" property="stuname"/>
</case>
<case value="52" resultType="com.lifen.entity.Student">
<result column="stuName" property="stuname"/>
</case>
</discriminator>
11.<where> <trim> 标签
<where>只能处理开头的
<trim>可以处理开头和结尾的sql where 拼接
<trim prefix=’where’ suffixOverrides=’and’> 给拼接的SQL加prefix=’where’ 处理结尾的多余的and
<select id="selectByTrim" parameterType="Student" resultMap="BaseResultMap">
select stuNo, stuName, stuAge, classId,nickName
from student
<trim prefix="where" suffixOverrides="and">
<if test="stuname!=null and stuname!=''">
stuName like '%${stuname}%' and
</if>
<if test="stuage!=null and stuage!=''">
stuAge=#{stuage} and
</if>
</trim>
</select>
<trim prefix=’where’ prefixOverrides=’and’> 给拼接的SQL加prefix=’where’ 处理开头的多余的and
Prefix:拼接
prefixOverrides:删除
12.内置参数
_parameter:代表mybatis的输入参数。
_databaseId:当前数据库类型的名字
13.模糊查询
a.${}: 原样输出 N‘%${}%’%
#{}:自动添加引号
b.传值时,直接传%x%
student.setStuName(“%s%”);
stuName like #{stuName}
c.bind参数
<bind name=”_queryName” value=”’%’+stuName+’%’”/>
通过bind将传入的stuName进行了处理
14.逆向工程