文章目录
用于映射数据库RUID操作,将SQL语句和Java接口进行绑定
基于XML方式映射SQL
定义XML SQL配置文件
StudentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.john.spring.mapper.StudentMapper">
<select id="queryAll" resultType="Student">
select * from student;
</select>
</mapper>
定义对应的mapper接口
StudentMapper.java
public interface StudentMapper {
List<Student> queryAll();
}
XML Mapper详解
< insert >、< delete >、< update >
< insert >、< delete >、< update >三个标签分别用来映射插入、删除、更新语句,实现非常类似,下面是他们的使用示例
<insert id="insertAuthor">
insert into Author (id,username,password,email,bio) values (#{id},#{username},#{password},#{email},#{bio});
</insert>
<update id="updateAuthor">
update Author set username = #{username},password = #{password},email = #{email},bio = #{bio} where id = #{id};
</update>
<delete id="deleteAuthor">
delete from Author where id = #{id};
</delete>
处理主键的自动生成
<!-- 获取数据库(如mysql、sqlserver)自增的id -->
<insert id="insertAuthor" useGeneratedKeys="true" keyProperty="id">
insert into Author (username,password,email,bio) values (#{username},#{password},#{email},#{bio});
</insert>
<!-- 批量插入,并获取自增的id -->
<insert id="insertAuthor" useGeneratedKeys="true" keyProperty="id">
insert into Author (username, password, email, bio) values
<foreach item="item" collection="list" separator=",">
(#{item.username}, #{item.password}, #{item.email}, #{item.bio})
</foreach>
</insert>
< insert >、< delete >、< update >标签可用属性说明
属性 | 描述 |
---|---|
id | 命名空间中的唯一标识符,可被用来代表这条语句。 |
parameterType | 将要传入语句的参数的完全限定类名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器推断出具体传入语句的参数,默认值为未设置(unset)。 |
parameterMap | 这是引用外部 parameterMap 的已经被废弃的方法。请使用内联参数映射和 parameterType 属性。 |
flushCache | 将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:true(对于 insert、update 和 delete 语句)。 |
timeout | 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖驱动)。 |
statementType | STATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。 |
useGeneratedKeys | (仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段),默认值:false。 |
keyProperty | (仅对 insert 和 update 有用)唯一标记一个属性,MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,默认值:未设置(unset)。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 |
keyColumn | (仅对 insert 和 update 有用)通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望使用多个生成的列,也可以设置为逗号分隔的属性名称列表。 |
databaseId | 如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。 |
示例
jdbc.properties数据源
jdbc.url=jdbc:mysql://localhost:3306/yanfa5
jdbc.driver=com.mysql.jdbc.Driver
jdbc.user=root
jdbc.password=root
jdbc.characterEncoding=utf8
StudentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace对应空Dao接口的全名 -->
<mapper namespace="com.lanou3g.mybatis.dao.StudentDao">
<!-- 当数据库表里的字段名和其实体类中的属性名不一样时需加下列配置 -->
<resultMap id="student" type="Student">
<!-- property的值为实体类中的属性名,column的值为数据库表的字段名 -->
<result property="id" column="sid" />
<result property="name" column="sname" />
<result property="age" column="sage" />
<result property="sex" column="ssex" />
</resultMap>
<!-- 此处的id是查询语句的名称,对应接口中的方法名 -->
<insert id="insertStudent">
insert into student (sname,sage) values (#{name},#{age});
</insert>
<update id="updateStudent">
update student set sage=#{age} where sid=#{id};
</update>
<delete id="deleteStudent">
delete from student where sid=#{id};
</delete>
</mapper>
mybatis.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties" />
<typeAliases>
<typeAlias type="com.lanou3g.mybatis.bean.Student" alias="Student" />
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/StudentMapper.xml" />
</mappers>
</configuration>
对应数据库表的java类
@Setter
@Getter
public class Student {
private Integer id;
private String name;
private Integer age;
private String sex;
private Integer leaderid;
@Override
public String toString() {
return "Student{" +
"sid=" + id +
", sname='" + name + '\'' +
", sage=" + age +
", ssex='" + sex + '\'' +
", leaderid=" + leaderid +
"}\n";
}
}
dao层
public interface StudentDao {
//多个参数需加个标记@Param
int insertStudent(@Param("name") String name,@Param("age") int age);
int updateStudent(@Param("age") int age,@Param("id") int id);
int deleteStudent(@Param("id") int id);
}
程序运行入口
public class App {
public static void main(String[] args) throws IOException {
//1、读入配置文件
String confPath = "mybatis.xml";
InputStream is1 = Resources.getResourceAsStream(confPath);
//2、构建SqlSessionFactory(用于获取sqlSession)
SqlSessionFactory sessionFactory1 = new SqlSessionFactoryBuilder().build(is1,"development");
//3、获取sqlSession对象(用于具体的RUID)
SqlSession sqlSession1 = sessionFactory1.openSession(true);
//4、具体的RUID
StudentDao studentDao = sqlSession1.getMapper(StudentDao.class);
//增
System.out.println("插入行数:"+studentDao.insertStudent("哈哈",45));
//改
System.out.println("修改行数:"+studentDao.updateStudent(12,103));
//删
System.out.println("删除行数:"+studentDao.deleteStudent(149));
}
}
< select >
< select >标签用于定义查询语句
简单示例
<select id="selectPerson" parameterType="int" resultType="hashmap">
SELECT * FROM PERSON WHERE ID = #{id};
</select>
上面的配置告诉mybatis需要创建一个像下面这样的预处理语句:
// 近似的 JDBC 代码,非 MyBatis 代码...
String selectPerson = "SELECT * FROM PERSON WHERE ID=?";
PreparedStatement ps = conn.prepareStatement(selectPerson);
ps.setInt(1,id);
select标签所支持的属性说明
属性 | 描述 |
---|---|
id | 在命名空间中唯一的标识符,可以被用来引用这条语句。 |
parameterType | 将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler) 推断出具体传入语句的参数,默认值为未设置(unset)。 |
parameterMap | 这是引用外部 parameterMap 的已经被废弃的方法。请使用内联参数映射和 parameterType 属性。 |
resultType | 从这条语句中返回的期望类型的类的完全限定名或别名。 注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。可以使用 resultType 或 resultMap,但不能同时使用。 |
resultMap | 外部 resultMap 的命名引用。结果集的映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂映射的情形都能迎刃而解。可以使用 resultMap 或 resultType,但不能同时使用。 |
flushCache | 将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。 |
useCache | 将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。 |
timeout | 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖驱动)。 |
fetchSize | 这是一个给驱动的提示,尝试让驱动程序每次批量返回的结果行数和这个设置值相等。 默认值为未设置(unset)(依赖驱动)。 |
statementType | STATEMENT,PREPARED 或 CALLABLE 中的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。 |
resultSetType | FORWARDONLY,SCROLLSENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖驱动)。 |
databaseId | 如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。 |
resultOrdered | 这个设置仅针对嵌套结果 select 语句适用:如果为 true,就是假设包含了嵌套结果集或是分组,这样的话当返回一个主结果行的时候,就不会发生有对前面结果集的引用的情况。 这就使得在获取嵌套的结果集的时候不至于导致内存不够用。默认值:false。 |
resultSets | 这个设置仅对多结果集的情况适用。它将列出语句执行后返回的结果集并给每个结果集一个名称,名称是逗号分隔的。 |
示例(单表查询)
jdbc.properties数据源
jdbc.url=jdbc:mysql://localhost:3306/yanfa5
jdbc.driver=com.mysql.jdbc.Driver
jdbc.user=root
jdbc.password=root
jdbc.characterEncoding=utf8
StudentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace对应空Dao接口的全名 -->
<mapper namespace="com.lanou3g.mybatis.dao.StudentDao">
<!-- 当数据库表里的字段名和其实体类中的属性名不一样时需加下列配置 -->
<resultMap id="student" type="Student">
<!-- property的值为实体类中的属性名,column的值为数据库表的字段名 -->
<result property="id" column="sid" />
<result property="name" column="sname" />
<result property="age" column="sage" />
<result property="sex" column="ssex" />
</resultMap>
<!-- 此处的id是查询语句的名称,对应接口中的方法名 -->
<!-- 无参 -->
<select id="queryAll" resultMap="student">
select * from student;
</select>
<!-- 单参 -->
<select id="queryById" parameterType="int" resultMap="student">
select * from student where sid = #{id};
</select>
<!-- 多参 -->
<select id="queryByIdAndAge" resultMap="student">
select * from student where sid <= #{id} and sage <= #{age};
</select>
</mapper>
mybatis.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties" />
<typeAliases>
<typeAlias type="com.lanou3g.mybatis.bean.Student" alias="Student" />
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/StudentMapper.xml" />
</mappers>
</configuration>
对应数据库表的java类
@Setter
@Getter
public class Student {
private Integer id;
private String name;
private Integer age;
private String sex;
private Integer leaderid;
@Override
public String toString() {
return "Student{" +
"sid=" + id +
", sname='" + name + '\'' +
", sage=" + age +
", ssex='" + sex + '\'' +
", leaderid=" + leaderid +
"}\n";
}
}
dao层接口(操作数据库)
public interface StudentDao {
//无参
List<Student> queryAll();
//单参
List<Student> queryById(int id);
//多参 当参数为多个时需要加一个标记对应StudentMapper.xml里#{XXX}中的XXX
List<Student> queryByIdAndAge(@Param("id") int id, @Param("age") int age );
}
程序运行入口
public class App {
public static void main(String[] args) throws IOException {
//1、读入配置文件
String confPath = "mybatis.xml";
InputStream is1 = Resources.getResourceAsStream(confPath);
//2、构建SqlSessionFactory(用于获取sqlSession)
SqlSessionFactory sessionFactory1 = new SqlSessionFactoryBuilder().build(is1,"development");
//3、获取sqlSession对象(用于具体的RUID)
SqlSession sqlSession1 = sessionFactory1.openSession(true);
//4、具体的RUID
StudentDao studentDao = sqlSession1.getMapper(StudentDao.class);
System.out.println(studentDao.queryAll());
System.out.println(studentDao.queryById(105));
System.out.println(studentDao.queryByIdAndAge(123,56));
}
}
结果集映射
< resultMap >
用途:
1. 数据库字段名和POJO属性名不一致
xml需要配置下列属性
<resultMap id="student" type="Student">
<result property="id" column="sid" />
<result property="name" column="sname" />
<result property="age" column="sage" />
<result property="sex" column="ssex" />
</resultMap>
2. 多表关联查询
resultMap通常用于比较复杂的结果集映射(如:多表关联查询)的情况,使用步骤如下:
- 显示定义标签映射结果集
<resultMap id="userResultMap" type="User"> <id property="id" column="user_id" /> <result property="username" column="user_name"/> <result property="password" column="hashed_password"/> </resultMap>
- 在查询语句中引用我们定义的resultMap:
<select id="selectUsers" resultMap="userResultMap"> select user_id, user_name, hashed_password from some_table where id = #{id} </select>
多表关联查询(级联查询)示例
< resultType >
直接映射成简单数据类型
<select id="selectUsers" resultType="map">
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
映射成自定义POJO
<select id="selectUsers" resultType="com.someapp.model.User">
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
-
上述示例中resultType还可以通过配置别名减少代码书写量
-
当我们配置resultType是自定义的POJO类型时,其实mybatis在底层也是通过帮我们生成一个配置来实现的
如果数据库字段和POJO中不一致时
- 通过sql查询别名
<select id="selectUsers" resultType="User">
select
user_id as "id",
user_name as "userName",
hashed_password as "hashedPassword"
from some_table
where id = #{id};
</select>
- 通过显示定义< resultMap >标签解决
<resultMap id="student" type="Student">
<!-- property的值为数据库表对应类中的属性名,column的值为数据库表中的字段名 -->
<result property="id" column="sid" />
<result property="name" column="sname" />
<result property="age" column="sage" />
<result property="sex" column="ssex" />
</resultMap>
参数
简单类型参数
示例:
<select id="selectUsers" resultType="User" parameterType="int">
select id, username, password from users where id = #{id};
</select>
上面的这个示例说明了一个非常简单的命名参数映射。参数类型被设置为 int,这样这个参数就可以被设置成任何内容。原始类型或简单数据类型(比如 Integer 和 String)因为没有相关属性,它会完全用参数值来替代。
复杂类型参数
示例:
<insert id="insertUser" parameterType="User">
insert into users (id, username, password) values (#{id}, #{username}, #{password});
</insert>
我们将User 类型的参数对象传递到了语句中,id、username 和 password 属性将会被查找,然后将它们的值传入预处理语句的参数中。
#{}与${}
默认情况下,使用 #{} 格式的语法会导致 MyBatis 创建 PreparedStatement 参数占位符并安全地设置参数(就像使用 ? 一样)。 这样做更安全,更迅速,通常也是首选做法,不过有时你就是想直接在 SQL 语句中插入一个不转义的字符串。 比如,像 ORDER BY,你可以这样来使用:
ORDER BY ${columnName}
这里 MyBatis 不会修改或转义字符串。
典型的应用场景:
像这样的三个方法
@Select("select * from user where id = #{id}")
User findById(@Param("id") long id);
@Select("select * from user where name = #{name}")
User findByName(@Param("name") String name);
@Select("select * from user where email = #{email}")
User findByEmail(@Param("email") String email);
我们可以直接用一个替代
@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String value);
按名称引用参数
由于Java编译是默认只会保留方法参数类型,方法参数名称会被丢掉,mybatis 3.4.3之前我们在映射文件中只能通过#{param1}, {param2}…来按顺序引用传进来的参数
<select id="queryByIdAndAge" resultType="Teacher">
select * from teacher where id = #{param1} and age <= #{param2};
</select>
@Param注解
我们在处理一个带有多个形参的构造方法时,很容易搞乱 arg 元素的顺序。 从版本 3.4.3 开始, 我们可以通过名称来引用构造方法参数,通过给方法参数添加 @Param 注解。用法:
Java代码
List<Teacher> queryByIdAndAge(@Param("tid") int id, @Param("age") int age);
Xml代码
<select id="queryByIdAndAge" parameterType="int" resultType="Teacher">
select * from teacher where id = #{tid} and age <= #{age};
</select>
基于XML方式映射SQL示例
jdbc.properties数据源
jdbc.url=jdbc:mysql://localhost:3306/yanfa5
jdbc.driver=com.mysql.jdbc.Driver
jdbc.user=root
jdbc.password=root
jdbc.characterEncoding=utf8
StudentMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace对应空Dao接口的全名 -->
<mapper namespace="com.lanou3g.mybatis.dao.StudentDao">
<!-- 此处的id是查询语句的名称,对应接口中的方法名 -->
<select id="queryAll" resultType="Student">
select * from student;
</select>
</mapper>
mybatis.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties" />
<typeAliases>
<typeAlias type="com.lanou3g.mybatis.bean.Student" alias="Student" />
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/StudentMapper.xml" />
</mappers>
</configuration>
对应数据库表的java类
@Setter
@Getter
public class Student {
private Integer sid;
private String sname;
private Integer sage;
private String ssex;
private Integer leaderid;
@Override
public String toString() {
return "Student{" +
"sid=" + sid +
", sname='" + sname + '\'' +
", sage=" + sage +
", ssex='" + ssex + '\'' +
", leaderid=" + leaderid +
"}\n";
}
}
dao层接口(操作数据库)
public interface StudentDao {
List<Student> queryAll();
}
程序运行入口
public class App {
public static void main(String[] args) throws IOException {
//1、读入配置文件
String confPath = "mybatis.xml";
InputStream is = Resources.getResourceAsStream(confPath);
//2、构建SqlSessionFactory(用于获取sqlSession)
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
//3、获取sqlSession对象(用于具体的RUID)
SqlSession sqlSession = sessionFactory.openSession();
//4、具体的RUID
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
System.out.println(studentDao.queryAll());
}
}
基于注解方式映射SQL
示例:
public interface TeacherMapper {
@Insert("insert into teacher(tname) values (#{tname})")
int insertTeacher(Teacher teacher);
}
mybatis最初设计时就是一个基于XML驱动的框架。虽然从Mybatis3开始Mybatis支持了很多基于注解方式的配置,但从实际使用来看,也仅适用于比较简单的场景下。像一些比较复杂的结果集映射用注解写出来可读性和可维护性就很低。
上面并不是说注解配置就一无是处, 比如一些简单的单表RUID语句我们就可以直接通过注解来配置, 而不在需要单独写一个XML映射文件
基于注解方式映射SQL示例
jdbc.properties数据源
jdbc.url=jdbc:mysql://localhost:3306/yanfa5
jdbc.driver=com.mysql.jdbc.Driver
jdbc.user=root
jdbc.password=root
jdbc.characterEncoding=utf8
mybatis.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties" />
<typeAliases>
<typeAlias type="com.lanou3g.mybatis.bean.Student" alias="Student" />
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="com.lanou3g.mybatis.dao.TeacherDao" />
</mappers>
</configuration>
对应数据库表的java类
@Getter
@Setter
public class Teacher {
private Integer tid;
private String tname;
private Integer cid;
@Override
public String toString() {
return "Teacher{" +
"tid=" + tid +
", tname='" + tname + '\'' +
", cid=" + cid +
"}\n";
}
}
dao层接口(操作数据库)
public interface TeacherDao {
//查询语句
@Select("select * from teacher")
List<Teacher> queryAll();
}
程序运行入口
public class App {
public static void main(String[] args) throws IOException {
//1、读入配置文件
String confPath = "mybatis.xml";
InputStream is = Resources.getResourceAsStream(confPath);
//2、构建SqlSessionFactory(用于获取sqlSession)
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
//3、获取sqlSession对象(用于具体的RUID)
SqlSession sqlSession = sessionFactory.openSession();
//4、具体的RUID
TeacherDao teacherDao = sqlSession.getMapper(TeacherDao.class);
System.out.println(teacherDao.queryAll());
}
}