CREATE TABLE `db`.`student_info`( `id` INT NOT NULL, `name` CHAR(20), `age` INT, `sex` CHAR(20), PRIMARY KEY (`id`) );
INSERT INTO `db`.`student_info` (`id`, `name`, `age`, `sex`) VALUES ('1', 'Tom', '20', 'male');
INSERT INTO `db`.`student_info` (`id`, `name`, `age`, `sex`) VALUES ('2', 'Lily', '21', 'female');
INSERT INTO `db`.`student_info` (`id`, `name`, `age`, `sex`) VALUES ('3', 'Lucy', '19', 'female');
INSERT INTO `db`.`student_info` (`id`, `name`, `age`, `sex`) VALUES ('4', 'Bruce', '22', 'male');
INSERT INTO `db`.`student_info` (`id`, `name`, `age`, `sex`) VALUES ('5', 'David', '20', 'male');
INSERT INTO `db`.`student_info` (`id`, `name`, `age`, `sex`) VALUES ('6', 'James', '23', 'male');
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="features"/>
typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value=""/>
<property name="url" value=""/>
<property name="username" value=""/>
<property name="password" value=""/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="mapper/StudentMapper.xml"/>
mappers>
configuration>
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.StudentMapper">
mapper>
package mapper;
import features.Student;
import java.util.List;
public interface StudentMapper {
}
package features;
public class Student {
private int id;
private String name;
private int age;
private String sex;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
<dependencies>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.10version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.30version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13.2version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>2.0.0version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.2.11version>
<scope>testscope>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-coreartifactId>
<version>1.2.11version>
dependency>
dependencies>

StudentMapper
List<Student> selectAll();
StudentMapper.xml
<select id="selectAll" resultType="Student">
select * from student_info;
select>
执行sql,之后的操作主要修改3中的代码,其他的代码可以直接复制过来
//1. 获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2. 获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//3. 获取Mapper接口的代理对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = mapper.selectAll();
System.out.println(students);
//4. 释放SqlSession
sqlSession.close();
id对应的数据StudentMapper
Student selectById(int id);
StudentMapper.xml
参数占位符:
#{}:会将=之后的内容替换为?,可以防止SQL注入
select * from student_info where id = ?;${}:拼sql,存在注入问题
select * from student_info where id = 1;转义字符处理:
<=>< <select id="selectById" resultType="Student">
select * from student_info where id = #{id};
select>
执行sql
Student student = mapper.selectById(1);
System.out.println(student);
假设我们需要查找年龄大于18岁的男性
StudentMapper
当存在多个变量的时候,我们需要用@Param进行标注。例如String sex只有标注了@Param("sex"),#{sex}才会知道传入的"male"是给它的。
如果你因为代码中存在三个sex而搞不懂它们之间的逻辑关系,不妨将String sex修改为String male_of_female然后重新运行一下程序,这是程序的结果不会发生变化。因为能够提示#{sex}它应该获取传入的哪个值的是@Param("sex"),而非String sex中的sex。
List<Student> selectByCondition(@Param("sex")String sex, @Param("age")int age);
StudentMapper.xml
<select id="selectByCondition" resultType="Student">
select * from student_info
where sex = #{sex}
and age > #{age};
select>
执行sql
List<Student> students = mapper.selectByCondition("male", 18);
System.out.println(students);
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。
如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。
StudentMapper
List<Student> selectByCondition(@Param("sex")String male_or_female, @Param("age")int age);
StudentMapper.xml
这里的if语句的含义是,如果传入的字符串sex不为null并且字符串不为空,那么增加一个sex=#{sex}的条件。当我们传入的sex值为male/female,该查询语句表示查询年龄大于18岁的男性/女性。当传入的sex为null或者"",该查询语句表示查询年龄大于18岁的所有人。
<select id="selectByCondition" resultType="Student">
select * from student_info
where age > #{age}
<if test="sex!=null and sex!=''">
and sex = #{sex}
if>
;
select>
执行sql
// 年龄大于18岁的男性
List<Student> students = mapper.selectByCondition("male", 18);
// 输出 4
System.out.println(students.size());
// 年龄大于18的男性或女性
List<Student> students = mapper.selectByCondition("", 18);
// 输出 6
System.out.println(students.size());
接下来我们尝试通过name和sex这两个条件进行查询
<select id="selectByCondition" resultType="Student">
select * from student_info
where
<if test="name!=null and name!=''">
name = #{name}
if>
<if test="sex!=null and sex!=''">
and sex = #{sex}
if>
;
select>
有一个比较尴尬的问题在于,如果传入的name和sex都为空,那么sql语句就变成了
select * from student_info where;
这显然是错误的。然而解决方式有两种,一种是在where后面加入恒等式,修改之后的代码是这样的:
<select id="selectByCondition" resultType="Student">
select * from student_info
where 1 = 1
<if test="name!=null and name!=''">
name = #{name}
if>
<if test="sex!=null and sex!=''">
and sex = #{sex}
if>
;
select>
但是这样的写法有一点捞,因为MyBatis早就预判了我们的预判,提供了
<select id="selectByCondition" resultType="Student">
select * from student_info
<where>
<if test="name!=null and name!=''">
name = #{name}
if>
<if test="sex!=null and sex!=''">
and sex = #{sex}
if>
where>
;
select>
然后我们对StudentMapper做一些修改
List<Student> selectByCondition(@Param("sex")String sex, @Param("age")int age);
然后试着运行一下
List<Student> students = mapper.selectByCondition("", "");
System.out.println(students.size()); // 6
List<Student> students = mapper.selectByCondition("male", "");
System.out.println(students.size());// 4
List<Student> students = mapper.selectByCondition("male", "Tom");
System.out.println(students.size()); // 1
choose:选择,类似于Java中的switch语句
StudentMapper
List<Student> selectByConditionSingle(@Param("sex")String sex, @Param("name")String name);
StudentMapper.xml
<select id="selectByConditionSingle" resultType="Student">
select * from student_info
where
<choose>
<when test="name!=null and name!=''">
name = #{name}
when>
<when test="sex!=null and sex!=''">
sex = #{sex}
when>
<otherwise>
1 = 1
otherwise>
choose>
;
select>
执行sql
List<Student> students = mapper.selectByConditionSingle("", "");
System.out.println(students.size());
StudentMapper
void add(Student student);
StudentMapper.xml
<insert id="add">
insert into student_info (id, name, age, sex)
values (#{id}, #{name}, #{age}, #{sex});
insert>
执行sql
Student student = new Student();
student.setId(7);
student.setName("Grace");
student.setAge(21);
student.setSex("female");
mapper.add(student);
// 提交事务
sqlSession.commit();
如果不想手动提交事务,也可以在sqlSessionFactory.openSession()中传入参数,即可自动提交事务:
SqlSession sqlSession = sqlSessionFactory.openSession(true);
这一部分我们尝试将Grace的年龄由21修改为22
StudentMapper
void update(Student student);
StudentMapper.xml
<update id="update">
update student_info
set
name = #{name},
age = #{age},
sex = #{sex}
where
id = #{id};
update>
执行sql
Student student = new Student();
student.setId(7);
student.setName("Grace");
student.setAge(22);
student.setSex("female");
mapper.update(student);
在2.7中我们尝试修改了Grace同学的年龄,但事实上我们也只是需要修改她的年龄,而无需修改其姓名、性别,可是碍于StudentMapper.xml中的代码,我们又不得不在创建Student对象实例时将姓名、性别信息添加进去。接下来介绍一种动态修改的方法,使得我们在update时无需将不需要改动的信息传入。
StudentMapper
void update(Student student);
StudentMapper.xml
<update id="update">
update student_info
<set>
<if test="name!=null and name!=''">
name = #{name},
if>
<if test="age!=null">
age = #{age},
if>
<if test="sex!=null and sex!=''">
sex = #{sex},
if>
set>
where
id = #{id};
update>
执行sql
Student student = new Student();
student.setId(7);
student.setAge(22);
mapper.update(student);
StudentMapper
void deleteById(int id);
StudentMapper.xml
<delete id="deleteById">
delete from student_info where id = #{id};
delete>
执行sql
mapper.deleteById(7);
StudentMapper
void deleteByIds(@Param("ids") int[] ids);
StudentMapper.xml
如果在StudentMapper的参数int[] ids前没有添加@Param("ids"),那么下面代码中的colletion值需要修改为array,因为在MyBatis中一个数组将会被封装为Map类型,其中key为array,value为该数组。
此外,由于删除的sql语句为delete from student_info where id in (id1,id2,...idn),而默认的,来分割每个id的,因此需要加上separator=","
<delete id="deleteByIds">
delete from student_info
where id in (
<foreach collection="ids" item="id" separator=",">
#{id}
foreach>
);
delete>
如果你觉得上面代码中in (xxx)的这组括号看着很别扭,也可以把它删去,然后在中添加open="(" close=")",这样在遍历前会添加上一个左括号,遍历结束会添加上一个右括号,完美!
执行sql
mapper.deleteByIds(new int[]{7,8});