MyBatis是一款优秀的特久层框架,用于简化JDBC开发。其是Apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis。2013年11月迁移到Github。由于MyBatis中的大部分API参数与数据库事务息息相关,因此事先了解下事务的知识,我个人觉得是很有必要的,我个人推荐zhihu的一篇文章《一文搞懂什么是事务》
官网:MyBatis中文网
为了应对JDBC内容中的硬编码和操作繁琐(见之前的文章),例如注册驱动、获取Connection连接以及SQL语句中的过程需要输入数据库驱动、数据库的账号密码,这需要重新编译和打包,然后后面获取petmt对象以及后续过程中,我们需要去手动设置参数或手动封装结果集,这都是繁琐的操作。因此MyBaits应运而生。MyBatis免除了几乎所有的JDBC代码以及设置参数和获取结果集的工作。
这里是自定义的名字,只是为了更好地引入Mapper映射地概念,所引入地一小节,其实也用到了Mapper映射。
首先再数据库里面创建一张user表,并添加数据
create database mybatis;
use mybatis;
drop table if exists tb_user;
create table tb_user(
id int primary key auto_increment,
username varchar (20),
password varchar(20),
gender char(1),
addr varchar(30)
);
INSERT INTO tb_user VALUES(1,'zhangsan','123','男','北京');
INSERT INTO tb_user VALUES(2,'李四','234','女','天津');
INSERT INTO tb_user VALUES(3,'王五','11','男','西安');
创建模块,导入坐标
创建新的模块,创建一个Maven的项目,然后再pom文件中添加mybatis的依赖(记得自行添加数据库等其他依赖)
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>x.x.xversion>
dependency>
编写MyBatis核心配置文件->替换连接信息解决硬编码问题,创建资源文件mybatis-config.xml
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybatis?useSSL=false"/>
<property name="username" value="$root"/>
<property name="password" value="1234"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="UserMapper.xml"/>
mappers>
configuration>
编写SQL映射文件->统一管理sq语句,解决硬编码问题,取名规则:取名规则一般按照需要操作的实体进行命名,例如我们这里举例为user为实体,则可以创建为UserMapper.xml
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="test">
<select id="selectAll" resultType="com.test.entity.User">
select * from tb_user
select>
mapper>
编码
// 定义P0J0类
package com.test.entity;
//αLt+鼠标左键整列编辑
public class User{
private Integer id;
private String username;
private String password;
private String gender;
private String addr;
public Integer getId(){
return id;
}
public void setId(Integer 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 String getGender(){
return gender;
}
public void setGender(String gender){
this.gender = gender;
}
public String getAddr(){
return addr;
}
public void setAddr(String addr){
this.gender = addr;
}
public String tostring(){
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", gender='" + gender + '\'' +
", addr='" + addr + '\'' +
'}';
}
}
// 加载核心配置文件,获取SqlSessionFactory对象
// 定义MyBaitsDemo类
package com.test;
/*
*Mybatis快速入门代码
*/
package com.test;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MyBatisDemo{
public static void main(String[]args) throws IOException{
//1.加截ybatis的核心置文件,获取SqlSessionFactory,同事这里包含了加载数据库驱动等一系列操作
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.SqlSession对象,用它来执行Sql
SqlSession sqlSession sqlSessionFactory.openSession();
//3.获取SqlSession对象,执行SQL语句 这里传入的字符串等于当时配置文件中写的标签
List<User> users = sqlSession.selectList("test.selectAll");
System.out.printIn(users);
// 释放资源
sqlSession.close();
}
}
解决Sql语句警告提示
如果在编译器中,Sql语句会标红,这是因为编译器(IDEA)与数据库没有没有建立连接,不识别表信息
**解决方案:**在Idea中配置MySQL数据库连接
输入账号密码和数据库名称,点击测试,没有报错,则连接成功。
在上面我们使用了“test.selectAll”的方式来执行sql语句,但是这样也不是很方便,因为我们需要写很多select id,而且不利于后期维护,并没有很好地改变硬编码的方式。于是我们引入了Mapper代理开发
目的
//原来的方式:
List<User>users = sqlSession.selectList(statemert:"test.selectAll");
System.out.println(users);
//现在的方式:
//3. 获取接口代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//4: 执行方法,其实就是执行sq1语句
List<User> users = userMapper.selectAll();
这样的方法有很多优势,首先它不依赖于字符串字面值,会更安全一点;其次,如果你的 IDE 有代码补全功能,那么代码补全可以帮你快速选择到映射好的 SQL 语句。
步骤
定义与SQL映射文件同名的Mapper接口,并且将Mapper接口和SQL映射文件放置在同一目录下,使用方式,在资源文件夹resources文件中创建对应路径的文件夹,例如com/test/mapper,注意这里一定是斜杠,不是点,并将对应的XML文件放入到该文件夹中。
设置SQL映射文件的namespace属性为Mapper接口全限定名
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.test.mapper.UserMapper">
<select id="selectAll" resultType="com.test.entity.User">
select * from tb_user
select>
mapper>
在Mapper接口中定义方法,方法名就是SQL映射文件中sql语句的id,并保持参数类型和返回值类型一致
// UserMapper.java
package com.test.mapper;
import com.test.entity.User;
import java.util.List;
public interface UserMapper{
List<User> selectAll();
}
编码
<mappers>
<mapper resource="com/test/mapper/UserMapper.xml"/>
mappers>
通过SqlSession的getMapper方法获取Mapper接口的代理对象
//3. 获取接口代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
* 调用对应方法完成sq的执行
```java
//4: 执行方法,其实就是执行sq1语句
List users = userMapper.selectAll();
细节:如果Mapper接口名称和SQL映射文件名称相同,并在同一目录下,则可以使用包扫描的方式简化SQL映射文件的加载
<mappers>
<package name="com.test.mapper"/>
mappers>
MybatisX是一款基于IDEA的快速开发插件,为效率而生。
使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL 语句更加混乱不堪。 因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句。
查询:在对应接口方法上写如下注解
@Select("select * from tb_user where id = #{id}")
添加
@Insert()
修改
@Update()
删除
@Delete()
SQL语句会随着用户的输入或外部条件的变化而变化,这就是动态SQL。
动态多条件查询
<select id="selectByCondition"resultMap="brandResultMap">
select *
from tb_brand
where 1 = 1
<if test="status != null">
and status = #{status}
if>
<if test="companyName != null and companyName != '' ">
and company_name like #{companyName}
if>
<if test="brandName != null and brandName != '' ">
and brand_name like #{brandName}
if>
select>
动态单条件查询
<select id="selectByConditionSingle" resultMap="brandResultMap">
select *
from tb_brand
where
<choose>
<when test="status != null">
status = #{status}
when>
<when test="companyName != null and companyName != ''">
company_name like #{companyName}
when>
<when test="brandName != null and brandName != ''">
brand_name like #{brandName}
when>
<otherwise>
1 = 1
otherwise>
choose>
select>
MyBatis事务
openSession():默认开启事务,进行增删改操作后需要使用sqlSession.commit(); //手动提交事务
openSession(true):可以设置为自动提交事务(关闭事务)
添加-主键返回
<insert id="addOrder" useGeneratedKeys="true" keyProperty="id">
insert into tb_order(payment,payment_type,status)
values (#{payment},#{paymentType},#{status});
insert>
<insert id="addOrderltem">
insert into tb_order_item(goods_name, goods_price, count, order_id)
values (#{goodsName},#{goodsPrice},#{count},#{orderId});
insert>
修改-修改动态字段
<update id="update">
update tb_brand
<set>
<if test="brandName != null and brandName !=''">
brand_name = #{brandName},
if>
<if test="companyName !=null and companyName !=''">
company_name = #{companyName},
if>
<if test="ordered != null">
ordered = #{ordered},
if>
<if test="description != null and description !=''">
description = #{description},
if>
<if test="status != null">
status = #{status}
if>
set>
where id =#{id};
update>
批量删除
<delete id="deleteByIds">
delete from tb_brand where id
in (
<foreach collection="ids" item="id" separator=",">
#{id}
foreach>
);
delete>
<delete id="deleteByIds">
delete from tb_brand where id
in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
foreach>
;
delete>
映射中数据库标的字段名称 和 实体类的属性名称 不一样
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="test">
<select id="selectAll" resultMap="userResultMap">
select * from tb_user
select>
mapper>
参数占位符、参数类型以及特殊字符处理
<select id="selectById"resultMap="userResultMap">
select
from tb_user where id = ${id};
select>
多条件查询下的多参数接收
散装参数:如果方法中有多个参数,需要使用@Param
selectByC(@Param(id)int id, @Param(client_name) String client_name));//在Mapper接口中通过注解告知所对应的参数
对象参数:对象的属性名称要与参数占位符的名称一致
selectByC(User user); //在Mapper接口中传递对象,在调用接口方法之前,必须先封装对象,并提供对应的属性值
map集合参数:键值的名称必须与参数占位符的名称一致
selectByC(Map map) //在Mapper接口中传递对象,在调用接口方法之前,必须先封装map集合对象,并提供键值对
MyBatis参数传递
单个参数
POJO类型:直接使用, 属性名 与 参数占位符名称 一致
Map集合:直接使用, 键名 与 参数占位符名称 一致
Collection:封装为Map集合
map.put("arg0",collection集合);
map.put("collection",collection集合);
List:封装为Map集合
map.put("arg0",List集合);
map.put("collection",List集合);
map.put("List",List集合);
Array
map.put("arg0",数组);
map.put("array",数组);
其他类型:直接使用
多个参数
ParamNameResolver类进行参数封装
默认将多个参数封装为集Map集合
// 在类ParamNameResolver类中使用getNameParams方法对参数进行封装,可以使用@Param注解,天幻Map集合中默认的arg键名
map.put("arg0",参数值1)
map.put("param1",参数值1)
map.pUt("param2",参数值2)
map.pUt("arg1",参数值2)