Mybatis使用及原理解析

时间:2022-10-31 17:42:51

MyBatis 是一个基于Java的持久层框架。它提供的持久层框架包括SQL Maps和Data Access Objects(DAO)。

MyBatis 是支持普通 SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJO(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录

每个MyBatis应用程序主要都是使用SqlSessionFactory实例的,一个SqlSessionFactory实例可以通过SqlSessionFactoryBuilder获得。SqlSessionFactoryBuilder从一个xml配置文件或者一个预定义的配置类的实例获得配置信息。

 
使用:

1准备资源

1.1数据库中建立相应的表

CREATE DATABASE mybatis;
USE mybatis;
CREATE TABLE tb_user(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(16),
age INT
);
INSERT INTO tb_user(NAME, age) VALUES('phf1', 12);
INSERT INTO tb_user(NAME, age) VALUES('phf2', 20);
INSERT INTO tb_user(NAME, age) VALUES('phf3', 30);

1.2 jar包

 

2.在eclipse中测试使用

 

2.1导入jar包。

 
 

2..2建一个mybatis-config.xml配置文件

可以在工程的src目录下
<?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">
<!-- XML 配置文件包含对 MyBatis 系统的核心设置,包含获取数据库连接实例的数据源和 决定事务范围和控制的事务管理器. -->
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
<!-- 给对象取别名 -->
<typeAliases>
<typeAlias alias="User" type="org.phf.pojo.User"/>
<typeAlias alias="Student" type="org.phf.pojo.Student"/>
<typeAlias alias="Clazz" type="org.phf.pojo.Clazz"/>
</typeAliases>
<!-- 配置JDBC连接参数 -->
<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://127.0.0.1:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 指明每个关系表的配置文件 -->
<mappers>
<mapper resource="org/phf/mapping/UserMapper.xml"/>
<mapper resource="org/phf/mapping/ClazzMapper.xml"/>
<mapper resource="org/phf/mapping/StudentMapper.xml"/>
</mappers>
</configuration>

2.3 为封装SqlSessionFactory建个单例


package org.phf.factory;

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;

public class MybatisFactory {
/**
* SqlSessionFactory对象可以看成DataSource(数据库连接池)
* 在应用执行期间,应该只创建一次,建议使用单例模式
* 通过SqlSessionFactoryBuilder来获得数据库配置参数并创建
*/
private static SqlSessionFactory sqlSessionFactory;

/**
* SqlSession对象可以理解成对Connection的封装,即一个数据连接会话
* 它同时也封装了连接和断开过程,提供sql语句的映射
* SqlSession实例不能被共享,它不是线程安全的。
* 所以应该一次性用完后要确保使用finally块来关闭它,关闭时会被收回SqlSessionFactory所管理的连接池中
*/
//private static SqlSession session;
static
{
try {
String resource = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
System.out.println(sqlSessionFactory);
} catch (Exception e) {
e.printStackTrace();
}
}
//
public static SqlSession getSqlSession()
{
return sqlSessionFactory.openSession();
}
//
public static void close(SqlSession session)
{
if(session != null)
session.close();
}
}
 

2.4为每个表建一个映射类

package org.phf.pojo;
/**
* 数据库表的映射类,每个实例对象映射到表中的一行数据
* 属性的名称和类型对应表中字段名和类型,并提供getter和setter方法
* @author Administrator
*/
public class User {
private Integer id;
private String name;
private Integer age;

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;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", age=" + age + "]\n";
}

}


2.5建XXXmapper.xml文件和XXXmapper.java接口文件

创建每个表映射类创建的XXXmapper.xml配置文件,并创建相应XXXmapper接口(即数据存取接口),mapper配置文件和接口文件放在同一包目录下
<!-- UserMapper.xml -->
<?xml version="1.0" encoding="gbk"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"mybatis-3-mapper.dtd">
<!-- MyBatis 真正的力量是在映射语句中。这里是奇迹发生的地方。
对于所有的力量,SQL 映射的 XML 文件是相当的简单。
当然如果你将它们和对等功能的 JDBC 代码来比较,你会 发现映射文件节省了大约 95%的代码量。
MyBatis 的构建就是聚焦于 SQL 的,使其远离于 普通的方式。Mybatis封装处理了连接和查询结果获取 -->
<mapper namespace="org.phf.mapping.UserMapper">

<!--开启缓存-->
<cache />
<!--
select 查询语句是使用 MyBatis 时最常用的元素之一。
id(方法)是 get, parameterType(参数类型)是Integer, resultType(返回类型)是 User对象,其属性就是列名,值是列对应的值。
-->
<select id="find" parameterType="Integer" resultType="User">
SELECT * FROM TB_USER WHERE ID = #{id}
</select>
<!--单条数据返回类型可以是HashMap,key为列名,value为值 -->
<select id="findMap" parameterType="Integer" resultType="HashMap">
SELECT * FROM TB_USER WHERE ID = #{id}
</select>

<!-- 返回多条数据时会自动封装成List集合返回-->
<select id="findAll" resultType="User">
SELECT * FROM TB_USER
</select>

<!-- 最多接受一个参数,所以多个参数可以封装成对象传参,可进行判断处理-->
<select id="findWithIf" parameterType="User" resultType="User">
SELECT * FROM TB_USER
<where>
<if test="name!= null">name = #{name}</if>
<if test="age!= null">and age = #{age}</if>
</where>
</select>
<!-- 多个键值对参数也可以用map传参,key对应列名-->
<select id="findByNameAndAge" parameterType="Map" resultType="User">
SELECT * FROM TB_USER
<where>
<if test="name!= null">name = #{name}</if>
<if test="age!= null">and age = #{age}</if>
</where>
</select>
<!-- 多个单值参数也可以用List传参,循环处理-->
<select id="findWithIn" parameterType="list" resultType="User">
SELECT * FROM TB_USER WHERE id IN
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
<!-- 多个单值参数也可以用List传参,循环处理-->
<select id="findWithLike" parameterType="String" resultType="User">
<bind name="pattern" value="'%' + _parameter + '%'" />
SELECT * FROM tb_user
WHERE name LIKE #{pattern}
</select>

</mapper>

//UserMapper.java
package org.phf.mapping;

import java.util.List;
import java.util.Map;

import org.phf.pojo.User;

/**
* 只要定义接口方法,所需sql语句在相应UserMapper.xml中映射
*/
public interface UserMapper {

//一条数据可以返回表对象,属性对应列名
User find(Integer id);
//一条数据还可以返回Map,key对应列名
Map findMap(Integer id);
//多条数据返回List集合
List<User> findAll();
//最多接受一个参数,所以多个参数可以封装成对象传参,
List<User> findWithIf(User user);
//多个键值对参数也可以用map传参,key对应列名,value对应列值
List<User> findByNameAndAge(Map<String, Object> map);
//多个单值参数也可以用List传参,条件中使用IN操作符
List<User> findWithIn(List<Integer> ids);
//条件中使用like操作符
List<User> findWithLike(String name);
}
 

2.6测试代码

package org.phf.test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;
import org.phf.factory.MybatisFactory;
import org.phf.mapping.UserMapper;
import org.phf.pojo.User;

public class TestUserMapper {

@Test
public void test()
{
SqlSession session = null;
try {
//获取SqlSession的对象(需要手动关闭该资源)
session = MybatisFactory.getSqlSession();
//获取业务接口,通过接口类型获取由mybatis生成的匿名实例
UserMapper userMapper = session.getMapper(UserMapper.class);
//调用接口方法,执行操作且获得数据

System.out.println("<---------find by id----------->");
User user = userMapper.find(1);
System.out.println(user);

System.out.println("<---------findMap----------->");
Map map = userMapper.findMap(2);
System.out.println(map);

System.out.println("<---------findAll----------->");
List<User> userList = userMapper.findAll();
System.out.println(userList);

System.out.println("<---------findWithIf----------->");
user = new User();
user.setName("phf");
userList = userMapper.findWithIf(user);
System.out.println(userList);

System.out.println("<---------findByNameAndAge----------->");
Map<String, Object> map1 = new HashMap<String, Object>();
map1.put("age", 10);
userList = userMapper.findByNameAndAge(map1);
System.out.println(userList);

System.out.println("<---------findWithIn----------->");
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(5);
list.add(10);
userList = userMapper.findWithIn(list);
System.out.println(userList);

System.out.println("<---------findWithLike----------->");
String likeName = "ph";
userList = userMapper.findWithLike(likeName);
System.out.println(userList);


} catch (Exception e) {
e.printStackTrace();
}
finally{
MybatisFactory.close(session);
}
}
}


 3.多对一,一对多 关联的处理

3.1数据库建两表

USE mybatis;
CREATE TABLE tb_clazz(
id INT PRIMARY KEY AUTO_INCREMENT,
CODE VARCHAR(16)
);

CREATE TABLE tb_student(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(32),
sex VARCHAR(2),
age INT ,
clazz_id INT,
CONSTRAINT clazz_fk FOREIGN KEY (clazz_id) REFERENCES tb_clazz(id)
);

INSERT INTO tb_clazz(CODE) VALUES('12345');
INSERT INTO tb_clazz(CODE) VALUES('11122');

INSERT INTO tb_student(NAME,sex,age,clazz_id) VALUES('phf1','男',12,1);
INSERT INTO tb_student(NAME,sex,age,clazz_id) VALUES('phf2','男',13,1);
INSERT INTO tb_student(NAME,sex,age,clazz_id) VALUES('phf3','男',25,1);
INSERT INTO tb_student(NAME,sex,age,clazz_id) VALUES('phf4','男',24,2);
INSERT INTO tb_student(NAME,sex,age,clazz_id) VALUES('phf5','女',23,1);
INSERT INTO tb_student(NAME,sex,age,clazz_id) VALUES('phf6','男',26,2);


3.2 表映射类

package org.phf.pojo;

public class Student {
private Integer id;
private String name;
private String sex;
private Integer age;
//多对一
private Clazz clazz;


public Student() {
super();
// TODO Auto-generated constructor stub
}
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 String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Clazz getClazz() {
return clazz;
}
public void setClazz(Clazz clazz) {
this.clazz = clazz;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", sex=" + sex
+ ", clazz=" + clazz + "]\n";
}
}

package org.phf.pojo;

import java.util.List;

public class Clazz {
private Integer id;
private String code;
//一对多
private List<Student> studentList;

public Clazz() {
super();
// TODO Auto-generated constructor stub
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}

public List<Student> getStudentList() {
return studentList;
}
public void setStudentList(List<Student> studentList) {
this.studentList = studentList;
}
@Override
public String toString() {
return "Clazz [id=" + id + ", code=" + code + ", studentList=\n"
+ studentList + "]";
}
}


3.3 XXXMapper.xml和XXXMapper.java接口文件

package org.phf.mapping;
import org.phf.pojo.Student;
public interface StudentMapper {
Student find(Integer id);
}

<!--StudentMapper.xml--->
<?xml version="1.0" encoding="gbk"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"mybatis-3-mapper.dtd">
<mapper namespace="org.phf.mapping.StudentMapper">
<!--开启缓存-->
<cache />
<!--resultMap标签将column属性(数据库表中的列名) 映射到 property属性(Student对象中的字段)-->
<resultMap id="clazzResult" type="Clazz">
<id column="id" property="id"/>
<result column="code" property="code"/>
</resultMap>

<resultMap id="studentResult" type="Student">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="sex" property="sex"/>
<result column="age" property="age"/>
<!--<association>标签体现的是多对一关联关系,-->
<association property="clazz" javaType="Clazz" resultMap="clazzResult"/>
</resultMap>

<select id="find" parameterType="Integer" resultMap="studentResult">
SELECT * FROM tb_student s,tb_clazz c
WHERE s.clazz_id=c.id AND s.id = #{id}
</select>
</mapper>

 
package org.phf.mapping;
import org.phf.pojo.Clazz;
public interface ClazzMapper {
Clazz find(Integer id);
}

<!---ClazzMapper.xml---->
<?xml version="1.0" encoding="gbk"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"mybatis-3-mapper.dtd">
<mapper namespace="org.phf.mapping.ClazzMapper">
<!--开启缓存-->
<cache />

<resultMap id="clazzResult" type="Clazz">
<id column="id" property="id"/>
<result column="code" property="code"/>
<collection property="studentList" ofType="Student"
column="id" select="findStudentById"/>
</resultMap>

<resultMap id="studentResult" type="Student">
<association property="clazz" javaType="Clazz" column="class_id" select="find"/>
</resultMap>

<select id="findStudentById" parameterType="Integer" resultMap="studentResult">
select * from tb_student where clazz_id=#{class_id}
</select>

<select id="find" parameterType="Integer" resultMap="clazzResult">
select * from tb_clazz where id=#{id}
</select>
</mapper>


3.4 在mybatis-config.xml文件中增加配置

 
	<typeAliases>
<typeAlias alias="User" type="org.phf.pojo.User" />
<typeAlias alias="Student" type="org.phf.pojo.Student" />
<typeAlias alias="Clazz" type="org.phf.pojo.Clazz" />
</typeAliases>

<mappers>
<mapper resource="org/phf/mapping/UserMapper.xml"/>
<mapper resource="org/phf/mapping/StudentMapper.xml"/>
<mapper resource="org/phf/mapping/ClazzMapper.xml"/>
</mappers>


3.5 测试代码增加

	@Test
public void testMulti()
{
SqlSession session = null;
try {
session = MybatisFactory.getSqlSession();
StudentMapper studentMapper = session.getMapper(StudentMapper.class);

System.out.println("<-----testMulti----Student--find by id------------>");
Student stu = studentMapper.find(1);
System.out.println(stu);

ClazzMapper clazzMapper = session.getMapper(ClazzMapper.class);
System.out.println("<-----testMulti---Clazz--find by id------------>");
Clazz clazz = clazzMapper.find(1);
System.out.println(clazz);

} catch (Exception e) {
e.printStackTrace();
}
finally{
MybatisFactory.close(session);
}
}