一、MyBatis介绍
MyBatis 本来是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis,实质上Mybatis对ibatis进行一些改进。 目前mybatis在github上托管。
在传统的jdbc编程中,我们可以注意到像注册驱动、创建connection、创建statement、手动设置参数、结果集检索等这些操作都是我们手动实现的,可以说代码很多很繁杂。而且,在jdbc中 sql语句是硬编码,如果需求变更了就需要修改java中的代码,然后重新编译,非常不利于维护。然而,MyBatis框架就可以帮我们解决这一些列问题。
MyBatis 是一个优秀的持久层框架,它对JDBC的操作数据库过程进行封装,是开发者只要专注于SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。MyBatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
二、MyBatis基本查询操作
准备工作:1. 创建测试项目 2. 导入两个jar包: mybatis-3.4.6.jar 和mysql-connection-java-8.0.11.jar
2.1 数据库建表(我这里建了一个订单表——orders)
先插入两条记录:
2.2 创建orders表的实体类——Order
import java.util.Date;
import java.util.List;
public class Order {
protected Integer id;
protected Integer user_id;
protected Integer number;
protected Date createtime;
protected String note;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUser_id() {
return user_id;
}
public void setUser_id(Integer user_id) {
this.user_id = user_id;
}
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
public Date getCreatetime() {
return createtime;
}
public void setCreatetime(Date createtime) {
this.createtime = createtime;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
@Override
public String toString(){
return "domain.order{" +"id="+id
+",userId="+user_id+",number="+number+",createtime="+createtime+",note="+note+"}";
}
}
2.3 配置 配置xml文件 :SqlMapConfig.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事务管理 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 数据连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/first_mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8"></property>
<property name="username" value="root"></property>
<property name="password" value="yooneiweiyoonei."></property>
</dataSource>
</environment>
</environments>
</configuration>
2.4 配置 Mapper xml 文件 :OrderMaper.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.xml文件中配置很多的sql语句,执行每个sql语句时,分装为MapperStatement对象 mapper.xml以statement为单位管理sql语句 -->
<!-- mapper标签中 namespace参数值为之后我们要创建的代理接口类的全限定名 -->
<mapper namespace="mapper.OrderMapper">
<!-- 根据id查询订单信息 -->
<!--
id:唯一标识 一个statement 这里对应我们之后要创建代理接口类中的方法名
#{}:表示 一个占位符,如果#{}中传入的是简单类型的参数,#{}中的名称可以随意取
parameterType:输入 参数的类型,通过#{}接收parameterType输入的参数 这里对应我们之后要创建的代理接口类对应方法中的参数类型
resultType:输出结果类型,不管返回多条还是单调,指定单挑记录映射的pojo类型(plain old java object 普通java对象)。这里对应我们以后要创建代理接口类对应方法的返回值类型。
-->
<select id="findOrderById" parameterType="int" resultType="domain.Order" >
select * from orders where id=#{id}
</select>
</mapper>
列表结构:
注意将OrderMapper.java 和OrderMapper.xml文件 放在一个包下。
2.5 在SqlMapConfig文件中注册OrderMapper.xml文件
在SqlMapConfig.xml中添加一个<mappers></mappers>
字段,并在里面传入OrderMapper.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事务管理 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 数据连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/first_mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8"></property>
<property name="username" value="root"></property>
<property name="password" value="yooneiweiyoonei."></property>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/OrderMapper.xml"></mapper>
</mappers>
</configuration>
2.6 写Mapper.java的代理接口类
package mapper;
import domain.Order;
public interface OrderMapper {
public Order findOrderById(int id) throws Exception;
}
2.7 写dao层
package dao;
import java.io.IOException;
import java.io.InputStream;
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 domain.Order;
import mapper.OrderMapper;
public class Dao {
private SqlSessionFactory sqlSessionFactory;
//初始化方法,创建sqlSessionFactory工厂对象用于之后的SqlSession的创建
public void init() throws IOException{
String resource="SqlMapConfig.xml";
InputStream inputStream=Resources.getResourceAsStream(resource);
sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
}
public String findOrderById(int id) throws Exception {
SqlSession sqlSession=sqlSessionFactory.openSession();//创建会话
OrderMapper orderMapper=sqlSession.getMapper(OrderMapper.class);//获取代理类对象
Order result=orderMapper.findOrderById(id);//调用代理类方法
sqlSession.close();//关闭会话
return result.toString();
}
}
2.8 写测试类
package Demo;
import dao.Dao;
public class Demo1 {
public static void main(String[] args) throws Exception {
Dao dao=new Dao();
dao.init();//初始化
String result=dao.findOrderById(1);
System.out.println(result);
}
}
控制台显示结果
当我们使用模糊查询的时候,传入参数的地方不再使用#{}而是要使用${},如下:
<select id="findOrderLike" parameterType="java.lang.String" resultType="domain.Order">
select * from orders where note like '%${value}%'
</select>
#{}和${}的区别:
#{}
:1.表示一个占位符,向占位符输入参数,mybatis自动进行java类型和jdbc类型的转换。2.程序员不需要考虑参数的类型,比如:传入字符串,mybatis最终拼接好的sql就是参数两边加单引号。3.#{}
接收pojo(Plain Old Java Object Java数据对象)数据,可以使用OGNL(就是el表达式)解析出pojo的属性值。${}
:1.表示sql的拼接,通过${}
接收参数,将参数的内容不加任何修饰拼接在sql中。2.${}
也可以接收pojo数据,可以使用OGNL解析出pojo的属性值。3.缺点:不能防止sql注入。
三、Mybatis基本增删改操作
3.1.使用Mybatis向表中插入记录:
1.在OrderMapper.xml添加如下字段:
<!-- 添加用户 -->
<!--
parameterType:输入参数的类型 ,这里输入参数为Order对象 包括了Order的id,user_id,number,createtime,note;
#{}接受pojo数据,可以通过OGNL解析出pojo的属性值
#{id},#{user_id},#{number},#{createtime},#{note} 表示从parameterType中取出的pojo的属性值
-->
<insert id="insertOrder" parameterType="domain.Order">
insert into orders values(#{id},#{user_id},#{number},#{createtime},#{note})
</insert>
2.在OrdeMapper.java 接口中添加insertOrder(Order order)方法
package mapper;
import domain.Order;
public interface OrderMapper {
public Order findOrderById(int id) throws Exception;
public void insertOrder(Order order) throws Exception;
}
3.在Dao中添加insertOrder(Order order) 方法
package dao;
import java.io.IOException;
import java.io.InputStream;
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 domain.Order;
import mapper.OrderMapper;
public class Dao {
private SqlSessionFactory sqlSessionFactory;
// 初始化方法,创建sqlSessionFactory工厂对象用于之后的SqlSession的创建
public void init() throws IOException{
String resource="SqlMapConfig.xml";
InputStream inputStream=Resources.getResourceAsStream(resource);
sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
}
public String findOrderById(int id) throws Exception {
SqlSession sqlSession=sqlSessionFactory.openSession();//创建会话
OrderMapper orderMapper=sqlSession.getMapper(OrderMapper.class);//获取代理类对象
Order result=orderMapper.findOrderById(id);//调用代理类方法
sqlSession.close();
return result.toString();
}
public void insertOrder(Order order) throws Exception{
SqlSession sqlSession=sqlSessionFactory.openSession();
OrderMapper orderMapper=sqlSession.getMapper(OrderMapper.class);
orderMapper.insertOrder(order);
sqlSession.commit();//增,删,改 这类更新数据库操作都需要用commit()方法提交会话
sqlSession.close();//关闭会话
}
}
4.编写测试类:
package Demo;
import java.util.Date;
import dao.Dao;
import domain.Order;
public class Demo1 {
public static void main(String[] args) throws Exception {
Dao dao=new Dao();
dao.init();//初始化
// String result=dao.findOrderById(1);
// System.out.println(result);
//
Order order=new Order();
order.setId(3);
order.setUser_id(3);
order.setNumber(6);
order.setCreatetime(new Date());
order.setNote("aha mybatis");
dao.insertOrder(order);
System.out.print("insert success!");
}
}
此时查看控制台和数据库,发现数据已经被插入,结果如下:
控制台:
数据库:
扩展:主键返回
现在,我们还是利用测试类在数据库orders表中插入一条记录,不同的是 我们现在不给Order对象的id属性设置值,如下:
package Demo;
import java.util.Date;
import dao.Dao;
import domain.Order;
public class Demo1 {
public static void main(String[] args) throws Exception {
Dao dao=new Dao();
dao.init();//初始化
// String result=dao.findOrderById(1);
// System.out.println(result);
Order order=new Order();
order.setUser_id(4);
order.setNumber(8);
order.setCreatetime(new Date());
order.setNote("oh mybatis");
dao.insertOrder(order);
System.out.print("insert success!");
}
}
因为我们在数据库建orders表时定义了id字段为自增长的主键,所以在数据库中orders的id字段是有值的,如下:
但当我们在测试类中尝试输出Order对象的id时会输出id=0。那么,当我们想输出改对象在记录中的id时,该怎么做呢?只需要在OrderMapper.xml文件中的<insert></insert>标签中添加<selectKey>标签就可以了。如下:
<insert id="insertOrder" parameterType="domain.Order">
<!-- keyProperty:将主键值设置到哪个属性
resultType: select LAST_INSERT_ID()的结果 类型
order:属性值AFTER表示该字段在执行insert语句后才执行
另外 我们需要借助LAST_INSERT_ID()函数 -->
<selectKey keyProperty="id" order="AFTER" resultType="int">
select LAST_INSERT_ID()
</selectKey>
insert into orders values(#{id},#{user_id},#{number},#{createtime},#{note})
</insert>
此时,我们在测试类中就可以输出改Order对象插入在表中的记录id值了。
这里我们由于在建表时设置了id字段为自增长,采用自增长的形式生成主键,所以我们在传入User对象的id属性时可以将该属性设置为null。那么当我们使用uuid生成主键时又该怎么做呢?
只需要在OrderMapper.xml中添加如下字段:
<!-- keyProperty:将主键值设置到哪个属性
resultType: select LAST_INSERT_ID()的结果 类型
order:属性值“AFTER” 表示该字段在执行insert语句后才执行,属性值“BEFORE” 表示在执行插入时,会先调用uuid()函数得到主键,然后将主键设置到Order对象中,再插入到数据库。
另外 我们需要借助LAST_INSERT_ID()函数 -->
<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
select uuid()
</selectKey>
insert into orders values(#{id},#{user_id},#{number},#{createtime},#{note})
但是需要注意的是,我们在数据库和映射对象中定义了id字段为int类型,如果要用uuid()生成的String类型值作为id字段的属性值,我们还需要修改orders表和Order对象的类型为String,否侧编译器会抛出异常。
3.2.使用Mybatis实现更行表中数据
1.在OrderMapper.xml 文件中添加如下字段:
<update id="updateOrder" parameterType="domain.Order">
update orders set user_id=#{user_id},number=#{number},createtime=#{createtime},note=#{note} where id=#{id}
</update>
2.在OrderMapper.java 接口中添加对应方法:
public void updateOrder(Order order) throws Exception;
3.在Dao层中添加对应方法:
public void updateOrder(Order order) throws Exception{
SqlSession sqlSession=sqlSessionFactory.openSession();
OrderMapper orderMapper=sqlSession.getMapper(OrderMapper.class);
orderMapper.updateOrder(order);
sqlSession.commit();
sqlSession.close();
}
4.编写测试类:
package Demo;
import java.util.Date;
import dao.Dao;
import domain.Order;
public class Demo1 {
public static void main(String[] args) throws Exception {
Dao dao=new Dao();
dao.init();//初始化
// String result=dao.findOrderById(1);
// System.out.println(result);
// Order order=new Order();
order.setId(5)
// order.setUser_id(4);
// order.setNumber(8);
// order.setCreatetime(new Date());
// order.setNote("ohye mybatis");
// dao.insertOrder(order);
// System.out.print("insert success!");
Order order1=new Order();
order1.setId(5);
order1.setUser_id(4);
order1.setNumber(8);
order1.setCreatetime(new Date());
order1.setNote("this is a update Order");
dao.updateOrder(order1);
System.out.print("update success!");
}
}
控制台输出结果:
数据库更新前和更新后结果:
3.3 使用Mybatis 实现删除表中数据
基本和以上操作差不多
1.在Order.xml文件中添加如下字段:
<delete id="deleteOrderById" parameterType="int">
delete from orders where id=#{id}
</delete>
2.在Order.java接口中添加对应方法:
public void deleteOrderById(int id) throws Exception;
3.在Dao层添加对应方法:
public void deleteOrderById(int id) throws Exception{
SqlSession sqlSession=sqlSessionFactory.openSession();
OrderMapper orderMapper=sqlSession.getMapper(OrderMapper.class);
orderMapper.deleteOrderById(id);
sqlSession.commit();
sqlSession.close();
}
4.测试类中编写对应代码:
package Demo;
import java.util.Date;
import dao.Dao;
import domain.Order;
public class Demo1 {
public static void main(String[] args) throws Exception {
Dao dao=new Dao();
dao.init();//初始化
// String result=dao.findOrderById(1);
// System.out.println(result);
// Order order=new Order();
// order.setUser_id(4);
// order.setNumber(8);
// order.setCreatetime(new Date());
// order.setNote("oh mybatis");
// dao.insertOrder(order);
// System.out.print("insert success!");
// Order order1=new Order();
// order1.setId(5);
// order1.setUser_id(4);
// order1.setNumber(8);
// order1.setCreatetime(new Date());
// order1.setNote("this is a update Order");
// dao.updateOrder(order1);
// System.out.print("update success!");
//
dao.deleteOrderById(5);
System.out.print("delete success");
}
}
查看数据库,发现对应id=5的记录已被删除
四、Mybatis利用代理开发流程小结
- 数据库建表
- 创建数据库中对应表的映射实体类
- 编写 SqlMapConfig.xml 配置文件
- 编写 mapper.xml
- 把mapper.xml文件注册到SqlMapConfig.xml配置文件中
- 编写mapper代理接口,添加对应statement方法
- 写Dao层对应操作方法
在Dao层中:
- 编程通过配置文件创造SqlSessionFactory
- 通过SqlSessionFactory获取SqlSession对象
- 通过SqlSession对象获取代理类对象
- 通过代理类操作数据库(如果执行添加、更新、删除需要调用SqlSession.commit())
- SqlSesion使用完成要关闭