一.简介
MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。
MyBatis 消除 了几乎所有的 JDBC 代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML 或注解用于配置和原始映射,将接口和 Java 的 POJOs(Plain Ordinary Java Objects,普通的 Java 对象)映射成数据库中的记录。
MyBatis的前身是iBatis,MyBatis在iBatis的基础上面,对代码结构进行了大量的重构和简化;
二.第一个程序(3.1.1)
1.导入相关的包资源
2.添加著主配置文件(mybatis-config.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>
<!-- 和spring整合后 environments配置将废除-->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理,事务控制由mybatis,该处是别名-->
<transactionManager type="JDBC" />
<!-- 数据库连接池,由mybatis管理,该处是别名-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql:///mybatisdemo" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/mxl/mybatis01_hello/UserMapper.xml"></mapper>
</mappers>
</configuration>
3.添加domain文件(User)
package com.mxl.mybatis01_hello;
public class User {
private Long id;
private String username;
private String password;
private Integer age;
public User() {
}
public User(Long id, String username, String password, Integer age) {
this.id = id;
this.username = username;
this.password = password;
this.age = age;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", age=" + age +
'}';
}
}
4.需要添加domain文件的映射信息(USerMapper.xml)
需要注意的两点是:
1.mapper的namespace中写的是所在包名加上mapper文件名
namespace=“com.mxl.mybatis01_hello.UserMapper”
2.配置自增的id注入对象中
<?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.mxl.mybatis01_hello.UserMapper">
<!--
inser表示插入语句
parameterType表示调用insert传入的参数
keyColumn表示数据库中自增长的字段名
keyProperty表示自增长的字段值应该注入到实体中的哪个字段
useGeneratedKeys表示标记这个标签需要使用数据库中的自增长id
-->
<insert id="save" parameterType="com.mxl.mybatis01_hello.User" keyColumn="id" keyProperty="id" useGeneratedKeys="true">
insert into t_user(username,password,age) values (#{username},#{password},#{age})
</insert>
</mapper>
5.将domain的配置文件添加到主配置文件中
<mappers>
<mapper resource="com/mxl/mybatis01_hello/UserMapper.xml"></mapper>
</mappers>
6.编写测试类,保存对象
注意:session.insert中的statement为namespace加id
public class TestCRUD {
@Test
public void test1() throws IOException {
User u = new User();
u.setUsername("撒旦");
u.setPassword("123456");
u.setAge(13);
SqlSessionFactory sf = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession session = sf.openSession();
session.insert("com.mxl.mybatis01_hello.UserMapper.save",u);
session.commit();
session.close();
System.out.println(u);
}
}
三.监控sql语句
1.在资源目录下添加log4j.preperties并添加如下配置:
高光处应该写自己的namespace的包名或者父包名.
log4j.logger.com.mxl.mybatis01_hello=TRACE
# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.com.mxl.mybatis01_hello=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
四.更新操作:
Usermapper.xml中添加:
<update id="update" parameterType="com.mxl.mybatis01_hello.User">
update t_user set username=#{username},password=#{password},age=#{age} where id = #{id}
</update>
测试类中添加:
@Test
public void test2() throws IOException {
User u = new User();
u.setId(1L);
u.setUsername("马欣龙");
u.setPassword("123");
u.setAge(22);
SqlSessionFactory sf = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession session = sf.openSession();
session.update("com.mxl.mybatis01_hello.UserMapper.update",u);
session.commit();
session.close();
System.out.println(u);
}
此时发现每个测试方法中都要写
SqlSessionFactory sf = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession session = sf.openSession();
抽取mybatisUtils工具类
public class MybatisUtils {
private SqlSessionFactory sf = null;
private static MybatisUtils instance = new MybatisUtils();
private MybatisUtils(){
try {
sf = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
}catch (Exception e){
e.printStackTrace();
}
}
public static SqlSession openSession(){
return instance.sf.openSession();
}
}
五.查询单个对象操作:
Usermapper.xml中添加:
特别注意:要加resultType:表示查询出来的每一条结果封装成User对象
如果没写则报如下错误:
Caused by: org.apache.ibatis.executor.ExecutorException: A query was run and no Result Maps were found for the Mapped Statement ‘com.mxl.mybatis01_hello.UserMapper.get’. It’s likely that neither a Result Type nor a Result Map was specified.
<!--
parameterType:
resultType:表示查询出来的每一条结果封装成User对象
-->
<select id="get" parameterType="java.lang.Long" resultType="com.mxl.mybatis01_hello.User">
select id,username,password,age from t_user where id = #{id}
</select>
测试类中添加:
@Test
public void test3() throws IOException {
SqlSession session = MybatisUtils.openSession();
User u = session.selectOne("com.mxl.mybatis01_hello.UserMapper.get", 3L);
session.close();
System.out.println(u);
}
六.查询所有操作:
Usermapper.xml中添加:
<!--
parameterType:
resultType:表示查询出来的每一条结果封装成User对象
-->
<select id="list" resultType="com.mxl.mybatis01_hello.User">
select * from t_user
</select>
测试类中添加:
@Test
public void test4() throws IOException {
SqlSession session = MybatisUtils.openSession();
List<User> list = session.selectList("com.mxl.mybatis01_hello.UserMapper.list");
session.close();
for (User user : list) {
System.out.println(user);
}
}
七.删除操作:
Usermapper.xml中添加:
<delete id="delete" parameterType="java.lang.Long">
delete from t_user where id = #{id}
</delete>
测试类中添加:
@Test
public void testDelete() throws IOException {
SqlSession session = MybatisUtils.openSession();
session.delete("com.mxl.mybatis01_hello.UserMapper.delete", 2L);
session.commit();
session.close();
}
八.补充内容:
mybatis中提供了很多别名,比如java.lang.Long的别名为小写的long.
parameterType="long"相当于parameterType=“java.lang.Long”
九.自定义别名
1.在主配置文件mybatis-config.xml中添加
<!--定义别名:
type:需要定义别名的类的全限定名
alias:定义的别名
-->
<typeAliases>
<typeAlias type="com.mxl.mybatis01_hello.User" alias="User"/>
</typeAliases>
2.在UserMapper中就可以使用User的别名了
<select id="list" resultType="User">
select * from t_user
</select>
十.使用db.properties配置
方式一:
1.新建db.properties文件.
2.主配置文件中使用占位符的方式定义数据库连接信息.
<dataSource type="POOLED">
<property name="driver" value="${db.driverClassName}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</dataSource>
3.在mybatisUtils类中创建sqlsessionfactory的时候传入properties对象
try {
Properties p = new Properties();
p.load(Resources.getResourceAsReader("db.properties"));
sf = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"),p);
}catch (Exception e){
e.printStackTrace();
}
方式二:
1.新建db.properties文件.
2.直接在主配置文件中配置
<properties resource="db.properties"/>
十一.使用Mapper接口的方式
使用statementID的方式存在如下问题
①.传入的statement字符串有可能会写错,写错的时候必须等到运行的时候才发现
②.传入的参数无法限定类型.
使用Mapper接口的方式
1.新键UserMapper接口(确保以下几点)
接口的全限定名 等于 UserMapper.xml中的namespace
接口中的方法 等于 UserMapper.xml中标签中的id
接口方法上的参数 等于 UserMapper.xml中的parameterType
接口方法上的返回值类型 等于 UserMapper.xml的resultType
对应的API为:
UserMapper mapper = session.getMapper(UserMapper.class);
十二.ResultMap映射
当查询出来的字段名和对象中的属性名不一致的情况,就没办法使用resultType来默认映射(同名规则)
解决方案:
使用resultMap来映射数据库中的字段到底注入到对象中什么属性中.
1.在UserMapper.xml文件中定义resultMap标签
<resultMap id="base_map" type="User">
<!--
column:查询出来的字段名
property:对象中属性名
-->
<id column="d_id" property="id"></id>
<result column="d_username" property="username"></result>
<result column="d_password" property="password"></result>
<result column="d_age" property="age"></result>
</resultMap>
2.在查询标签中使用resultMap=”base_map”
<!--
resultType:表示查询出来的每一条结果封装成User对象
resultType与resultMap不可混用
-->
<select id="list" resultMap="base_map">
select id as d_id,username as d_username,password as d_password,age as d_age from t_user
</select>
十三.动态sql
1.条件查询
创建一个查询对象类QueryObject
public class QueryObject {
private String keyWord;
private Integer beginAge;
private Integer endAge;
//getter setter方法略去
}
在UserMapper.xml中添加如下代码
注意:id中的内容应该与UserMapper接口中的方法名保持一致,否则报错!!!
注意:模糊查询语法like concat(’%’,#{keyWord},’%’)中
concat的使用—单引号的使用
注意:(大于号> >小于号 < <)
注意如果要大于(小于)等于,等于号必须紧跟在>(<)后,中间不能有空格
<!--条件查询
注意:id中的内容应该与UserMapper接口中的方法名保持一致,否则报错!!!
where标签
if标签
注意:模糊查询语法like concat('%',#{keyWord},'%'),concat的使用以及单引号的使用
注意:(大于号> >小于号 < <)
注意如果要大于(小于)等于,等于号必须紧跟在>(<)后,中间不能有空格
-->
<select id="selectByCondition" parameterType="com.mxl.mybatis01_hello.QueryObject" resultType="User">
select * from t_user
<where>
<if test="keyWord!=null">
and username like concat('%',#{keyWord},'%')
</if>
<if test="beginAge!=null">
and age >= #{beginAge}
</if>
<if test="endAge!=null">
and age <= #{endAge}
</if>
</where>
</select>
Usermapper接口中给出相应的方法
List<User> selectByCondition(QueryObject qo);
测试类中给出相应测试方法
@Test
public void testQuery(){
SqlSession session = MybatisUtils.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
QueryObject qo = new QueryObject();
// qo.setKeyWord("东");
qo.setBeginAge(2);
qo.setEndAge(18);
List<User> list = mapper.selectByCondition(qo);
for (User user : list) {
System.out.println(user);
}
session.close();
}
2.动态更新
UserMapper.xml中添加如下
该处犯错
首先where不能丢掉
每个if语句后要加上逗号,不加报错!!!
<!--动态更新
首先where不能丢掉
每个if语句后要加上逗号,不加报错!!!
-->
<update id="updateDy" parameterType="User">
update t_user
<set>
<if test="username!=null">
username = #{username},
</if>
<if test="password!=null">
password = #{password},
</if>
<if test="age!=null">
age = #{age},
</if>
</set>
where id = #{id}
</update>
接口中给出相应的方法
void updateDy(User u);
测试类中编写测试方法
@Test
public void testUpdateDy(){
SqlSession session = MybatisUtils.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
User u = new User();
u.setId(8L);
u.setUsername("卡萨丁");
u.setPassword("666");
u.setAge(11);
mapper.updateDy(u);
session.commit();
session.close();
}
trim的使用
trim的属性:
prefix表示使用前缀
suffix表示使用的后缀
prefixOverrides表示前缀需要覆盖的内容
suffixOverrides表示后缀需要覆盖的内容
UserMapper.xml中
查询中原来的where可以用trim标签加上特定的属性来替代
and与where(覆盖最前面的and)
<select id="selectByCondition" parameterType="com.mxl.mybatis01_hello.QueryObject" resultType="User">
select * from t_user
<trim prefix="where" prefixOverrides="and">
<if test="keyWord!=null">
and username like concat('%',#{keyWord},'%')
</if>
<if test="beginAge!=null">
and age >= #{beginAge}
</if>
<if test="endAge!=null">
and age <= #{endAge}
</if>
</trim>
</select>
动态更新中原来的set可以用trim标签加上特定的属性来替代
逗号与set(覆盖最后一个逗号)
<update id="updateDy" parameterType="User">
update t_user
<trim suffixOverrides="," prefix="set">
<if test="username!=null">
username = #{username},
</if>
<if test="password!=null">
password = #{password},
</if>
<if test="age!=null">
age = #{age},
</if>
</trim>
where id = #{id}
</update>
foreach标签
迭代一个集合, 通常是构建在 IN 条件中的
foreach 元素是非常强大的,它允许你指定一个集合,声明集合项和索引变量,它们可 以用在元素体内。它也允许你指定开放和关闭的字符串,在迭代之间放置分隔符。这个元素 是很智能的,它不会附加多余的分隔符。
注意 你可以传递一个 List 实例或者数组作为参数对象传给 MyBatis。当你这么做时 ,MyBatis 会自动将它包装在一个 Map 中,用名称在作为键。List 实例将会以“list” 作为键,而数组实例将会以“array”作为键。
需求:查询id为4,5,6,7,8的用户
Mapper文件中的代码如下:
open和close配置的是以什么符号将这些集合元素包装起来
collection:选择list集合
separator:是各个元素的间隔符
item:配置的是循环中当前的元素
<select id="selectForEach" resultType="User">
select * from t_user where id in
<foreach collection="list" open="(" close=")" separator="," item="value">
#{value}
</foreach>
</select>
Mapper接口中
List<User> selectForEach(List<Long> idList);
测试类中代码
@Test
public void testForEach() {
SqlSession session = MybatisUtils.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
List<Long> list = new ArrayList<Long>();
list.add(4L);
list.add(5L);
list.add(6L);
list.add(7L);
list.add(8L);
List<User> userList = mapper.selectForEach(list);
for (User user : userList) {
System.out.println(user);
}
session.close();
}
十四.高级查询加分页
1.编写PageResult类
public class PageResult {
private Long total;
private List rows;
public static final PageResult EMPTY = new PageResult(0L,Collections.emptyList());
public PageResult(Long total, List rows) {
this.total = total;
this.rows = rows;
}
//略去setter和getter方法
}
2.在QueryObject类中添加:
//分页
private Long page;//当前页
private Long row;//每页显示几条数据
//略去getter,setter方法
3.编写IUserService接口
public interface IUserService {
PageResult list(QueryObject qo);
}
4.编写service实现类
public class UserServiceImpl implements IUserService{
public PageResult list(QueryObject qo) {
SqlSession session = MybatisUtils.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
try {
//查询总数
Long count = mapper.selectByConditionCount(qo);
if (count > 0){
List<User> result = mapper.selectByCondition(qo);
return new PageResult(count,result);
}else{
return PageResult.EMPTY;
}
} catch (Exception e) {
e.printStackTrace();
}
finally {
session.close();
}
return null;
}
}
5.在mapper配置文件中
<!--公共的查询条件-->
<sql id="condition">
<trim prefix="where" prefixOverrides="and">
<if test="keyWord!=null">
and username like concat('%',#{keyWord},'%')
</if>
<if test="beginAge!=null">
and age >= #{beginAge}
</if>
<if test="endAge!=null">
and age <= #{endAge}
</if>
</trim>
</sql>
<select id="selectByConditionCount" resultType="long">
select count(*) from t_user
<include refid="condition"/>
</select>
<select id="selectByCondition" parameterType="com.mxl.mybatis01_hello.domain.QueryObject" resultType="User">
select * from t_user
<include refid="condition"/>
limit #{start},#{row}
</select>
6.测试类
@Test
public void test() throws IOException {
QueryObject qo = new QueryObject();
qo.setKeyWord("东");
qo.setPage(1L);
qo.setRow(2L);
IUserService service = new UserServiceImpl();
PageResult page = service.list(qo);
System.out.println("总记录数: "+page.getTotal());
List<User> rows = page.getRows();
for (User u : rows) {
System.out.println(u);
}
}
}