首先,什么是MyBatis?
MyBatista属于ORM框架,是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射,对JDBC操作数据库的过程进行封装,使开发者只需要关注SQL本身。
这么说,可能有人不太理解,什么是ORM框架,什么又是持久层框架?
ORM即Object Relation Mapping的缩写,对象映射关系,基于关系型数据库的数据存储,实现一个虚拟的面向对象的数据访问接口,用于面向对象的对象模型和关系型数据之间的相互转换。
而持久层框架是在系统逻辑层面上,用于实现数据持久化(把数据保存到可掉电式存储设备中)的一个相对独立的领域,负责向(或从)一个或者多个数据存储器中存储(或获取)数据的一组类和组件。该层必须包括一个业务领域实体的模型。
MyBatis框架运行流程:
注:POJO全称是Plain Ordinary Java Object / Pure Old Java Object,中文可以翻译成:普通Java类,具有一部分getter/setter方法的那种类就可以称作POJO,实际就是普通JavaBeans,是为了避免和EJB混淆所创造的简称。
MyBatis配置文件:
SqlMapConfig.xml,是Mybatis的全局配置文件,配置了运行环境等信息。
Mapper.xml文件,即sql映射文件,配置了操作数据库的sql语句,配置这个文件,需要先在全局配置文件SqlMapConfig.xml中加载。
SqlSessionFactory:
生成SqlSession的工厂,作用是返回构造的SqlSession。
SqlSession:
是一个会话(Session),类似于JDBC里面的Connection,从开启这个会话,到结束这个会话,可以发送增删改查操作。
Executor:执行器接口
有两个实现,一个是基本执行器、一个是缓存执行器。
Mapped Statement:
是Mybatis的一个底层封装对象。封装了配置信息和sql映射等。
Mapper.xml与Mapped Statement的关联:Mapper.xml文件中一个sql对应一个Mapped Statement对象,其中的sql的id即是Mapped statement的id。
MyBatis具体实例(使用IDEA),
第一步,在MyBatis项目下加入一个lib的目录,lib下添加了相关jar包
asm各种版本下载:http://download.forge.ow2.org/asm/
cgllib的jar包下载:https://www.kumapai.com/open/1306-org-apache-servicemix-bundles-cglib
commons-logging的jar包下载:http://archive.apache.org/dist/commons/logging/binaries/
javassist的jar包下载:http://www.javassist.org/
loj4j的各种jar包下载:https://archive.apache.org/dist/logging/log4j/1.2.17/
https://archive.apache.org/dist/logging/log4j/2.0-rc1/
mybatis的jar包下载:https://www.kumapai.com/open/1306-org-apache-servicemix-bundles-mybatis
第二步,在src下面配置mybatis.xml全局配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration SYSTEM "http://mybatis.org/dtd/mybatis-3-config.dtd" PUBLIC "-//mybatis.org//DTD Config 3.0//EN">
-<configuration>
-<environments default="development">
<environment id="development">
<!-- 使用JDBC的事物管理 -->
<transactionManager type="JDBC"/>
<!-- 配饰数据库连接池 -->
<dataSource type="POOLED">
<property value="com.mysql.jdbc.Driver" name="driver"/>
<property value="jdbc:mysql://localhost:3306/java?characterEncoding=UTF-8" name="url"/>
<property value="root" name="username"/>
<property value="1234" name="password"/>
</dataSource>
</environment>
</environments>
</configuration>
第三步,在src下面创建包mybatis,在该包下创建存放实体类的包entity,在entity下创建实体类,
比如,我创建的是Student类
public class Student {
private Integer id;
private String name;
private Integer age;
private String gender;
private Integer banjiId;
public Student() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Integer getBanjiId() {
return banjiId;
}
public void setBanjiId(Integer banjiId) {
this.banjiId = banjiId;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", banjiId=" + banjiId +
'}';
}
为了使得配置文件扫描到包中的类,我们还需要在全局配置文件中加入typeAliases标签
<typeAliases>
<package name="mybatis.entity"/>
</typeAliases>
第四步,创建完实体类之后,在entity该包下创建对应的Mapper.xml,比如我创建的是
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="student">
</mapper>
不仅如此,还需要在全局配置文件中加载
<!-- 加载映射文件 -->
<mappers>
<mapper resource="mybatis/entity/StudentMapper.xml"/>
</mappers>
第五步,在StudentMapper.xml里面添加需要的sql语句,比如我要写一个select语句,在数据库中通过id查询student表里的数据(name,age,gender,banji_id)
<!-- 通过id查找学生 -->
<select id="selectById" parameterType="Integer" resultType="Student">
select id,name,age,gender,banji_id from student where id=#{id}
</select>
注:为了使类似banji_id这样有下划线的表中数据对应上banjiId这样小驼峰命名的类中属性,需要在全局配置文件mybatis.xml里面configuration标签内添加setting标签
<settings>
<!-- 下划线字段对应实体类驼峰命名 数据库表:banji_id 映射到类里面:banjiId -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
第六步,为了看到结果,在mybatis包下我建了一个test包,创建了一个MyBatisTest测试类
public class MyBatisTest {
@Test
public void testSelectById() throws IOException {
String resource = "mybatis.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建 SqlSessionFactory Session:会话 (连接数据库后就建立了一次会话,有了会话就可以操作数据库)
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 执行sql语句
Student student = sqlSession.selectOne("student.selectById", 1);
System.out.println(student);
}
}
执行这个函数,如果数据库中student表有一个id为1的数据,就会在控制台打印出来。
在这里,就会用到SqlSessionFactory以及SqlSession,但是,如果每一次使用,我们都要重复这些代码,因为我们写的这些只能在这个函数使用,就会有些繁琐了,所以把重复的代码封装成一个工具类,就会简化很多,比如我在mybatis包下创建了一个工具包util,在工具包下,创建了一个工具类,MyBatisUtil
public class MyBatisUtil {
private static SqlSessionFactory sqlSessionFactory;
static {
String resource = "mybatis.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession() {
// 得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
return sqlSession;
}
}
这样,在使用时,可以直接调用工具类封装的sqlSession对象,
@Test
public void testSelectById() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
// 执行sql语句
Student student = sqlSession.selectOne("student.selectById", 1);
System.out.println(student);
}
增删改查操作:
在StudentMapper.xml中
如果每次都要用到student表的id,name,age,gender,banji_id(这里是数据库表中显示的名字),都要自己写一遍,会很繁琐,所以,可以用sql标签,在使用时用include标签
<sql id="studentColumn">
id,name,age,gender,banji_id
</sql>
查找:
<select id="selectAll" resultType="Student">
select <include refid="studentColumn"></include>
from student
</select>
@Test
public void testSelectAll() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
List<Student> list = sqlSession.selectList("student.selectAll");
for (Student student : list) {
System.out.println(student);
}
}
删除(根据Id):
<delete id="deleteById" parameterType="Integer">
delete
from student
where id = #{id}
</delete>
@Test
public void testDeleteById() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
int count = sqlSession.delete("student.deleteById" , 3);
System.out.println(count);
sqlSession.commit();
sqlSession.close();
}
插入:
<insert id="insert" parameterType="Student">
insert into student(name, age, gender)
values (#{name}, #{age}, #{gender})
</insert>
@Test
public void testInsert() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
Student student = new Student();
student.setName("王柳");
student.setAge(23);
student.setGender("男");
int count = sqlSession.insert("student.insert", student);
System.out.println(count);
sqlSession.commit();
sqlSession.close();
}
更新(根据Id):
<update id="update" parameterType="Student">
update student
set name=#{name},
age=#{age},
gender=#{gender}
where id = #{id}
</update>
@Test
public void testUpdate() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
Student student = new Student();
student.setId(25);
student.setName("深蓝");
student.setAge(24);
student.setGender("男");
int count = sqlSession.update("student.update", student);
System.out.println(count);
sqlSession.commit();
sqlSession.close();
}
对于更新类的操作返回的是影响的函数,resultType不需要写;
对于更新类操作,sqlSession对象一定要提交,因为MyBatis把JDBC的autocommit(自动提交)设置为false,当执行更新类操作的时候并没有真正提交到数据库,需要手动提交。
resultType与parameterType:
result表示返回值,parameterType表示传递过来的参数
一些类型:
int/Integer/ineger:在配置int时通过上表可以看出,即可以是java中的基本类型int,也可以是java中的包装类型Integer,不过在配置为包装类型是必须是java.lang.Integer,所以在配置为int是我们的java接口中的参数类型最好是Integer的。
string/String:对应java中的java.lang.String
map:对应java.util.Map
hashmap:对应java.util.HashMap
list:对应java.util.List
arraylist:对应java.util.ArrayList
这些不需要我们自己映射,mybatis自己已经映射好了,我们使用的时候,只需要在Mapper.xml文件中直接写类型对应名字即可。
比如:
<select id="selectByPage" parameterType="Map" resultType="Student">
select<include refid="studentColumn"></include> from student limit #{offset}, #{pageSize}
</select>
@Test
public void testSelectByPage() {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
int pageNo = 2;
int pageSize = 5;
int offset = (pageNo - 1) * pageSize;
Map<String, Object> map = new HashMap<>();
map.put("offset", offset);
map.put("pageSize", pageSize);
List<Student> list = sqlSession.selectList("student.selectByPage", map);
for (Student student : list) {
System.out.println(student);
}
}
当实体类的属性名和表的字段名不一致的时候,一定要用resultMap映射之后才写sql语句,返回类型是resultMap的id名称 。不过通常情况下,即使我们表中名字和类中名字能够一一对应,也会用resultMap。
<resultMap type="Student" id="studentMap">
<!-- 映射主键属性:如果有多个主键字段,则定义多个id -->
<!-- property:类的属性名 -->
<!-- column:表的字段名 -->
<id property="id" column="id"/>
<!-- result定义普通属性 -->
<result property="name" column="student_name"/>
<result property="age" column="age"/>
<result property="gender" column="gender"/>
<result property="banjiId" column="banji_id"/>
</resultMap>
<select id="selectAll" resultMap="studentMap">
select id,student_name,age,gender,banji_id from student
</select>