1. 什么是mybatis
MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
2. mybatis入门
项目地址:https://github.com/zhongyushi-git/spring-collection.git。下载代码后,示例代码在mybatis-demo文件夹下。本项目是以原生的jar方式介绍的,同步的maven版本的代码见https://www.cnblogs.com/zys2019/p/14538018.html
2.1入门案例
第一步:先创建一个普通的ava工程
第二步:在根目录下新建一个lib目录
第三步:导入以下jar包
第四步:在src下新建config目录,创建db.properties文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db2020?characterEncoding=utf-8
jdbc.username=root
jdbc.password=zys123456
第四步:新建pojo实体类
package com.entity;
public class User {
private int id;
private String username;
private String password;
//get和set,toString方法在此略,使用时需要生成
}
第五步:创建一个接口用于访问数据库
package com.zxh.dao;
import com.zxh.entity.User;
import java.util.List;
public interface UserDao {
List<User> findAll();
}
接口中的方法要和select的id相同。
第六步:在src下新建mapper文件夹,在mapper下新建一个UserDao.xml文件:
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dao.UserDao">
<!--查询所有信息
id是这个select的唯一标识
resultType是返回类型
parameterType是参数类型
-->
<select id="findAll" resultType="com.dao.User">
select * from user
</select>
</mapper>
第七步:在config目录下新建配置文件SqlMapConfig.xml
<?xml version="1.0" encoding="uTF-8" ?>
<!-- mybatis核心配置 -->
<!-- 导入约束的路径 -->
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- 配置信息 -->
<configuration>
<!-- 引入并加载外部文件 -->
<properties resource="config/db.properties"></properties>
<!-- 给类取别名 -->
<typeAliases>
<!-- 使用包扫描方式取别名 -->
<package name="com.zxh.entity"/>
</typeAliases>
<!-- 环境配置的集合 -->
<environments default="mysql">
<environment id="mysql">
<!-- 事务管理:type指定事务的管理方式,jdbc:交给jdbc管理,MANAGED:被管理 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 数据库配置:type是否使用连接池,POOLED:使用连接池,UNPOOLED:不使用连接池 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!-- 加载映射文件 -->
<mappers>
<!-- 单独加载映射文件-->
<mapper resource="mapper/UserDao.xml"></mapper>
</mappers>
</configuration>
第八步:编写测试类
package com.zxh.test;
import com.zxh.dao.UserDao;
import com.zxh.entity.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.Reader;
import java.util.List;
public class MyTest {
@Test
public void findAll() throws IOException {
//加载核心配置文件
Reader reader = Resources.getResourceAsReader("config/SqlMapConfig.xml");
//创建SessionFactory
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(reader);
//创建一个session对象
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
List<User> list = userMapper.findAll();
System.out.println(list);
}
}
第八步:执行sql脚本
create database db2020;
CREATE TABLE user (
id int(11) NOT NULL,
username varchar(255) DEFAULT NULL,
password varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into user values(1,'admin','123');
insert into user values(2,'zhnagsan','456789');
insert into user values(3,'zxh','zxh');
第九步:测试。运行测试方法,在控制台打印了查询的结果。
2.2配置日志文件
已经导入了log4j的jar,主要是在这里使用。
1)在src新建一个log4j.properties文件,配置如下:
### 设置当前日志级别 ###
log4j.rootLogger = debug,stdout,D,E
### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
### 输出DEBUG 级别以上的日志到=E://logs/log.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
### 输出ERROR 级别以上的日志到=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =E://logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
需要注意的是,此文件名必须是log4j.properties,另外位置必须放在资源目录下(src根目录)。
2)在测试类中创建日志对象,把信息写到日志文件中,方便查阅:
//创建日志对象
Logger logger = Logger.getLogger(MyTest.class);
3)在查询的方法中添加一个日志的输出
logger.info("我是日志信息");
再次测试会在控制台输出一些日志,这句代码放在类中方法之前,debug信息会自动写到文件中,error信息要在发生异常的地方手动添加。
2.3自定义文件
每次创建xml都比较麻烦,可以自定义一个xml文件,使用起来方便点。操作如下图:
3. mybatis的增删改查
3.1方法优化
由于会重复的SqlSessionFactory对象,因此可以把其提取出来,在类加载时就初始化,提高代码复用性。因此,在测试类添加如下代码:
public SqlSessionFactory build = null;
//这个在方法加载的时候就会初始化
@Before
public void before() {
Reader reader = null;
//加载核心配置文件
try {
reader = Resources.getResourceAsReader("SqlMapConfig.xml");
//创建SessionFactory
build = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
}
}
3.2根据id查询
1)在userDao接口添加方法
User findById(Integer id);
2)在UserDao.xml中添加方法
<!-- 如果参数是简单数据类型,可以省略 -->
<select id="findById" parameterType="int" resultType="User">
select * from user where id=#{id}
</select>
3)新建测试方法
@Test
public void findById() {
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
User user = userMapper.findById(2);
System.out.println(user);
}
查询所有的方法在入门案例已介绍,在此略。
3.3根据用户名和密码查询
1)在userDao接口添加方法
User findByNmAndPwd(User user);
2)在UserDao.xml中添加方法
<select id="findByNmAndPwd" parameterType="User" resultType="User">
select * from user where username=#{username} and password=#{password}
</select>
#{ }里面的参数一定要和对象中的属性保持一致
3)新建测试方法
@Test
public void findByNmAndPwd(){
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
User user=new User();
user.setUsername("admin");
user.setPassword("123");
User user2 = userMapper.findByNmAndPwd(user);
System.out.println(user2);
}
3.4添加用户
1)在userDao接口添加方法
int addUser(User user);
2)在UserDao.xml中添加方法
<insert id="addUser" parameterType="User">
insert into user values(null,#{username},#{password})
</insert>
3)新建测试方法
@Test
public void addUser() {
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
User user = new User();
user.setUsername("方启豪5号");
user.setPassword("12315");
int i = userMapper.addUser(user);
session.commit();//提交事务
System.out.println(i);
}
增加、修改、删除修改一定要提交事务
3.5修改用户
1)在userDao接口添加方法
int updateUser(User user);
2)在UserDao.xml中添加方法
<update id="updateUser" parameterType="User">
update user set username=#{username},password=#{password} where id=#{id}
</update>
3)新建测试方法
@Test
public void updateUser() {
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
User user = new User();
user.setId(10);
user.setUsername("方启豪2号");
user.setPassword("123");
userMapper.updateUser(user);
session.commit();
}
3.6删除用户
1)在userDao接口添加方法
int deleteUser(Integer id);
2)在UserDao.xml中添加方法
<delete id="deleteUser"> delete from user where id=#{value} </delete>
3)新建测试方法
@Test
public void deleteUser() {
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
userMapper.deleteUser(10);
session.commit();
}
3.7模糊查询:一个条件
一个条件的模糊查询是特例,使用${},并且括号里面只能写value,这里参数是简单数据类型
1)在userDao接口添加方法
List<User> findByLikeOne(String username);
2)在UserDao.xml中添加方法
<!-- 模糊查询:一个条件,使用${},并且括号里面只能写value --> <select id="findByLikeOne" resultType="User"> select * from user where username like '%${value}%' </select>
3)新建测试方法
@Test
public void findByLikeOne() {
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
List<User> list = userMapper.findByLikeOne("h");
System.out.println(list);
}
3.8模糊查询:多个条件
使用${},并且括号里面要与对象的属性相同。
1)在userDao接口添加方法
List<User> findByLikeMore(User user);
2)在UserDao.xml中添加方法
<!-- 模糊查询:多个条件,使用${},并且括号里面要与对象的属性相同 --> <select id="findByLikeMore" parameterType="User" resultType="User"> select * from user where username like '%${username}%' and password like '%${password}%' </select>
3)新建测试方法
@Test
public void findByLikeMore() {
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
User user = new User();
user.setUsername("h");
user.setPassword("4");
List<User> list = userMapper.findByLikeMore(user);
System.out.println(list);
}
4. 章中小结
4.1#{}和${}的区别
(1)#{}
1)表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,可以有效防止sql注入。
2)可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
(2)${}
1)表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换
2) ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。
4.2parameterType和resultType
parameterType:指定输入参数类型
resultType:指定输出结果类型
4.3mybatis与hibernate的区别
Mybatis是对jdbc的封装,注重的是sql语句,是一种轻量级的半自动框架,适用于敏捷开发,原理是反射
Hibernate注重映射关系,是一种重量级的全自动的框架。
4.4取别名typeAliases
1)mybatis支持别名,映射关系如下表:
别名 | 映射的类型 | 别名 | 映射的类型 |
_byte | byte | string | string |
_long | long | byte | byte |
_short | short | long | long |
_int | int | short | short |
_integer | int | int | int |
_double | double | integer | Integer |
_float | float | double | Double |
_boolean | boolean | float | Float |
decimal | BigDecimal | boolean | Boolean |
bigdecimal | BigDecimal | map | Map |
2)自定义别名方法
在SqlMapConfig.xml中配置:
<typeAliases>
<!-- 单个别名定义 -->
<typeAlias alias="user" type="com.entity.User"/>
<!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) -->
<package name="com.entity"/>
<package name="其它包"/>
</typeAliases>
可以配置单个别名,也可以直接扫描整个包,建议使用第二种方式。
4.6mappers(映射器)
Mapper配置的几种方法:
代码 | 说明 | 示例 | 备注 |
<mapper resource=" " /> | 使用相对于类路径的资源 | <mapper resource="sqlmap/User.xml" /> | |
<mapper class=" " /> | 使用mapper接口类路径 | <mapper class="com.mapper.UserMapper"/> | 要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中 |
<package name=""/> | 注册指定包下的所有mapper接口 | <package name="com.mapper"/> | 要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中 |
4.7 dao接口开发规范
只需要编写Mapper接口,非常适用于mybatis,Mapper接口开发需要遵循以下规范,代码在入门中已说明这些:
1、Mapper.xml文件中的namespace与mapper接口的路径相同。
2、Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
3、Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
4、Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
5.resultMap与parameterMap
5.1复杂条件的查询举例
当参数不属于同一个对象时,使用简单的查询非常麻烦,那么可以把一个对象作为另一个对象的属性结合使用,示例如下。
1)新建三个实体类
Person类
package com.zxh.entity;
public class Person {
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
People类
package com.zxh.entity; public class People { private String password; public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
PVo类:把上面的两个对象作为属性给PVo
package com.zxh.entity;
public class PVo {
private People people;
private Person person;
//get/set方法略
}
2)新建接口方法
int addPvo(PVo pVo);
3)插入语句
<insert id="Pvo" parameterType="PVo"> insert into user values(12,#{person.username},#{people.password}) </insert>
4)测试方法
@Test public void addPvo() { SqlSession session = build.openSession(); UserDao userMapper = session.getMapper(UserDao.class); PVo pVo = new PVo(); People people = new People(); Person person = new Person(); people.setPassword("admin"); person.setUsername("zhangSan"); pVo.setPeople(people); pVo.setPerson(person); userMapper.addPvo(pVo); session.commit();//提交事务 }
5.2 resultMap的使用
当查询的结果不仅仅是一个对象的全部属性时,如果再创建一个对象来封装数据就显得格外的麻烦,那么可以使用resultMap来对属性进行重定义,这样就可以直接返回一个map的结果。具体的用法见代码中的注释。
5.2.1复杂查询一
查询用户的id,用户名以及所对应的成绩的id和具体成绩(一对一)
1)数据库执行sql
create table score ( id int primary key, grade float, u_id int ); insert into score values(1,99,1); insert into score values(2,90,2); insert into score values(3,85,3);
2)新建成绩类
package com.zxh.entity; public class Score { private int id; private double grade; private int u_id; public int getId() { return id; } public void setId(int id) { this.id = id; } public double getGrade() { return grade; } public void setGrade(double grade) { this.grade = grade; } public int getU_id() { return u_id; } public void setU_id(int u_id) { this.u_id = u_id; } @Override public String toString() { return "Score{" + "id=" + id + ", grade=" + grade + ", u_id=" + u_id + '}'; } }
3)给User类添加属性添加set和get及tostring方法
.... private Score score; ....
4)新建接口方法
List<User> findUserAndScore();
5)查询语句
<!-- 复杂查询:查询用户的id,用户名以及所对应的成绩的id和具体成绩 --> <!--定义表数据与组合类的映射关系,id是唯一标识,type是类型--> <resultMap id="userAndScore" type="User"> <!--id是主键映射,result是非主键映射,column是数据库中的列名,properties是对象的属性名--> <!--如果多个表中的属性名一样,要注意区分,如这里的id--> <id column="uid" property="id"></id> <result column="username" property="username"></result> <result column="password" property="password"></result> <!--association对属性是对象的变量的深入映射,适用于一对一的关系--> <association property="score" javaType="Score"> <id column="sid" property="id"></id> <result column="grade" property="grade"></result> <result column="u_id" property="u_id"></result> </association> </resultMap> <!--这里的返回类型必须是map集合--> <select id="findUserAndScore" resultMap="userAndScore"> select user.id uid, username,score.id sid,grade from user,score where user.id=score.u_id </select>
6)测试方法
@Test
public void findUserAndScore(){
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
List<User> list=userMapper.findUserAndScore();
System.out.println(list);
}
分析:在这对一对一的关系中,mybatis使用association来标识另一个对象属性,同时要指定返回的类型是map集合。
5.2.2复杂查询二
查询用户的id,用户名以及所对应的成绩的id和具体成绩(一对多)
1)在插入一条数据。此查询是基于上述查询一的,请按步骤进行。
insert into score values(4,75,2);
2)给User类添加属性并添加set和get及tostring方法
private List<Score> scores;
3)查询语句。需要把查询一的查询语句注释!
<resultMap id="userAndScore" type="User">
<id column="uid" property="id"></id>
<result column="username" property="username"></result>
<result column="password" property="password"></result>
<!--collection对属性是对象的变量的深入映射,适用于一对多的关系-->
<!--javaType指属性是什么类型,ofType指集合中装的什么类型-->
<collection property="scores" javaType="java.util.List" ofType="Score">
<id column="sid" property="id"></id>
<result column="grade" property="grade"></result>
<result column="u_id" property="u_id"></result>
</collection>
</resultMap>
<!--这里的返回类型必须是map集合-->
<select id="findUserAndScore" resultMap="userAndScore">
select user.id uid, username,score.id sid,grade from user,score where user.id=score.u_id
</select>
分析:在这对一对多的关系中,mybatis使用collection来标识另一个集合对象属性,同时要指定返回的类型是map集合。
6.动态sql
6.1 if标签
1)语法
当标签里面test的内容为true时才会去执行if里面的语句。
2)示例
查询:根据id或用户名查询
<select id="findByMap" resultType="User">
select * from user where 1=1
<if test="id!=null">
and id=#{id}
</if>
<if test="username!=null and username!=''">
and username like '%${username}%'
</if>
</select>
此查询语句中,分别以int类型的id和string类型的username进行判断查询。而id并没有判断是否是空串,原因是它不是字符串,同理date类型等其他类型都不能加是否是空串的条件判断,否则会报错。
6.2 where标签
1)语法
where会自动去识别,当sql语句中已经有where那么它会直接拼接where里面的内容,如果没有就直接使用;另外where里面的and也类似,如果已经有where就使用and,如果没有就舍弃第一个and。
2)示例
查询:根据id或用户名查询,如果都为空就查询所有
<select id="findById2" resultType="User">
select * from user
<where>
<if test="value!=null">
and id=#{value}
</if>
</where>
</select>
这个示例其实是对上面示例的对比,两种方式,查询的结果是一样的。
6.3 foreach标签
1)语法
用来遍历集合等,用于传入参数是多个相同类型的查询,可以使用在in,limit,between。。。
2)示例
查询:传入多个id的list集合查询用户信息
<select id="findByIn" parameterType="java.util.List" resultType="User">
select * from user
<!--如果传入参数是list类型,必须使用list获取,并且使用and-->
<if test="list.size()>0 and list!=null">
where id in
<!--collection要遍历的集合,open开始的符号,close结束的符号,separator分隔符-->
<!--index是索引,item是每一条内容,这里是list.get(i)-->
<foreach collection="list" open="(" separator="," close=")" index="i" item="item" >
#{item}
</foreach>
</if>
</select>
测试方法
@Test public void test4() { SqlSession session = build.openSession(); UserDao userMapper = session.getMapper(UserDao.class); List<Integer> list=new ArrayList<Integer>(); list.add(1); list.add(2); list.add(22); List<User> list2 = userMapper.findByIn(list); System.out.println(list2); }
6.4sql片段
将会重复使用的sql语句抽取出来,需要使用的地方直接引入
<!--sql片段-->
<sql id="select">
select * from user
</sql>
<select id="findById2" resultType="User">
<!--引入sql片段-->
<include refid="select"/>
where id=#{value}
</select>
7.延迟加载
需要查询关联信息时,我们先查询一部分信息,再关联查询关联信息,叫延迟加载。主要通过resultMap实现延迟加载。延迟加载需要导入cglib以及asm的jar包。
7.1打开延时加载的开关
在SqlMapConfig.xml中配置:
<settings>
<!-- 延迟加载开关 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 当设置为true的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载-->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
7.2写sql语句
根据用户名和密码查询出id,然后再根据id查询对应的成绩
查询之后可以看到先执行一次查询,然后再去执行后面的查询,并没有一次性查询出结果。
8. Mybatis缓存
将从数据库查询的数据存储到内存中缓存起来,这样就不用从数据库中查询数据而从缓存中查询,提高查询的速度,减少对数据库的访问。
8.1一级缓存
1)原理
当执行两条相同的查询语句时,mybatis只执行一次查询,map中存储了sql执行查询的结果集。是session级别的缓存,当执行增删改中的任何一个操作,缓存就会清空。
第一次查询先去缓存中找是否有缓存数据,发现没有,查询数据库,将查询到的数据写入sqlsession的一级缓存区域。
第二次查询先去缓存中找是否有缓存数据,发现有,直接从缓存区域中取出数据返回。如果执行sqlsession的添加、修改、删除等操作,会执行commit,最终会清空缓存。
2)一级缓存查询:
@Test
public void test6(){
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
User user = userMapper.findById(2);
System.out.println(user);
System.out.println("----------");
User user2=userMapper.findById(2);
System.out.println(user2);
}
从查询结果中可以看出只进行了一次的查询,第二次的查询直接从缓存中获取的。
3)一级缓存查询中执行增加操作:
@Test
public void test7(){
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
User user = userMapper.findById(2);
System.out.println(user);
User user3=new User();
user3.setUsername("方启豪6号");
user3.setPassword("12315");
userMapper.addUser(user3);
session.commit();//提交事务
System.out.println("----------");
User user2=userMapper.findById(2);
System.out.println(user2);
}
只要清空了session,那么就清除了缓存,就需要重新查询。也可以手动清空session,语句是
8.2二级缓存
1)原理
二级缓存是mapper(命名空间)级别的缓存,默认是开启的,只有session提交或关闭时才能把结果提交到二级缓存中,当执行增删改中的任何一个操作,缓存就会清空。
不同的sqlsession都要调用mapper下的sql语句发起数据库请求。sqlsession1执行UserMapper下的查询用户请求先从二级缓存中查找有没有数据,如果没有就从数据库中查询,并且将查询到数据存储二级缓存中。
sqlsession2执行UserMapper下的同一个查询用户请求,先从二级缓存中查找有没有数据,如果有就从二级缓存中查询数据,返回。
如果有一个sqlsession3执行UserMapper下添加、修改、删除语句,执行commit操作后,将UserMapper下的所有缓存数据全部清空。
2)二级缓存的使用
二级缓存的使用需要进行配置:
第一步:在SqlMapConfig.xml的settings中加一行代码:
<!--开启并标识二级缓存-->
<setting name="cacheEnabled" value="true"/>
第二步:在userDao.xml中加一行代码:
第三步:User类要实现Serializable接口
由于不经常使用,在此代码省略。
9. Mybatis注解
9.1@Param参数传入
当参数少于4个的时候可以使用注解参数的传入,如果参数过多,就使用原始pojo的方式
UserDao类:
//使用注解Param传递参数,引号里面的参数是要使用的参数,如#{username}
User findByNmAndPwd2(@Param("username")String username,@Param("password")String password);
userDao.xml中sql:
<select id="findByNmAndPwd2" resultType="User">
select * from user where username=#{username} and password=#{password}
</select>
测试类:
@Test
public void test8() {
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
User user = userMapper.findByNmAndPwd2("方启豪","123");
System.out.println(user);
}
9.2@Insert @Update @Delete
此注解不需要userDao.xml文件,这三个用法雷同,以update为例:
UserDao类:
//这里参数传的是一个对象
@Update("update user set username=#{user.username}, password=#{user.password} where id=#{user.id}")
void updateUser2(@Param("user")User user);
测试类:
@Test
public void test9() {
SqlSession session = build.openSession();
UserDao userMapper = session.getMapper(UserDao.class);
User user3 = new User();
user3.setId(10);
user3.setUsername("方启豪7号");
user3.setPassword("123155151");
userMapper.updateUser2(user3);
session.commit();
}
9.3@Select
此注解不需要userDao.xml文件
UserDao类:
@Select("select * from user where id=#{id}")
User findById2(@Param("id") Integer id);
测试类:
@Test
public void test10(){
SqlSession session = build.openSession();
UserDao mapper=session.getMapper(UserDao.class);
User user=mapper.findById(14);
System.out.println(user);
}
10.异常问题
10.1 Mybatis异常 There is no getter for property...
在dao层修改:
List<Article> recommandList(@Param("siteid") Integer siteid);
如上修改,给siteid @Param注入getter 即可。
总结:如果xml的parameterType属性时Map,则不需要加@Param。如果是一个int,string这种类型的参数,需要在Dao层加@Param注解;只有一个参数,xml不用if,可不加。有多个参数,dao层每个参数都要加上@Param。如果传入的参数特别多,建议直接传入一个Map。