Mybatis入门使用总结

时间:2022-04-02 05:12:58

1.什么是Mybatis

Mybatis原来是apache的一个开源项目ibatis,2010年这个项目由apache softwarefoundation迁移到了google code,并且改名为Mybatis。2013年11月迁移到了github。iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQLMaps和DataAccess Objects(DAO)。Mybatis实际也是一个orm解决方案之一。

2.mybatis入门程序

使程序与Mybatis可以顺利建立连接作为入门程序。

首先需要导入相关jar包:

Mybatis入门使用总结

工程目录,包括后面的程序:

Mybatis入门使用总结

从上图可以看出还需要编写一下log4j.properties便于我们查看日志。

测试连接的小程序:

/*
* 工具类
* */
public class MybatisUtil {
private static ThreadLocal<SqlSession> threadLocal =new ThreadLocal<SqlSession>();
private static SqlSessionFactory sqlSessionFactory;
/*
* 加载位于src/mybatis.xml配置文件
* */
static{
try {
Reader reader =Resources.getResourceAsReader("mybatis.xml");
sqlSessionFactory =new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new RuntimeException(e);
}
}
//禁止外部访问
private MybatisUtil(){}
/*
* 获取SqlSession
* */
public static SqlSession getSqlSession(){
//从当前线程中获取sqlSession对象
SqlSession sqlSession =threadLocal.get();
if(sqlSession ==null){
//如果sqlSessionFactory对象不为空情况下,那么获取SqlSession对象。
sqlSession =sqlSessionFactory.openSession();
//将sqlSession与当前线程绑定在一起
threadLocal.set(sqlSession);
}
//直接返回sqlSession对象
return sqlSession;
}


/*
* 关闭SqlSession与当前线程分离
* */
public static void closeSqlSession(){
//从当前线程中获取sqlSession对象
SqlSession sqlSession =threadLocal.get();
if(sqlSession !=null){
//关闭sqlSession对象
sqlSession.close();
//分开当前线程与sqlSession对象的关系,目的是让GC尽早回收
threadLocal.remove();
}
}
public static void main(String[] args) {
Connection conn =MybatisUtil.getSqlSession().getConnection();
System.out.println(conn !=null ?"连接成功":"连接失败");
MybatisUtil.closeSqlSession();
}
}

Mybatis.xml是Mybatis的总配置文件:

<?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>

<!-- 加载类路径下的属性文件 -->
<properties resource="db.properties"></properties>

<!-- 设置类型别名 -->
<typeAliases>
<typeAlias type="cn.spy.model.Student" alias="Student"/>
</typeAliases>

<environments default="mysql_developer">
<!-- mysql环境信息 -->
<environment id="mysql_developer">
<!-- mybatis使用jdbc事务管理方式 -->
<transactionManager type="jdbc"></transactionManager>
<!-- mybatis使用连接池方式来获取连接 -->
<dataSource type="pooled">
<!-- 配置与数据库交互的四个必要属性 -->
<property name="driver" value="${mysql.driver}"/>
<property name="url" value="${mysql.url}"/>
<property name="username" value="${mysql.username}"/>
<property name="password" value="${mysql.password}"/>
</dataSource>
</environment>
</environments>

<!-- 加载映射文件 -->
<mappers>
<mapper resource="cn\spy\model\StudentMapper.xml"/>
</mappers>
</configuration>
其实我们完全可以直接Mybatis中数据库必须配置的四个属性的位置,直接配置数据库的驱动,连接,用户名和密码。这样做不便于以后的修改。则直接采用properties文件配置。

db.properties数据库配置文件:

mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/basicjdbc?characterEncoding=utf-8
mysql.username=root
mysql.password=
至于Mybatis.xml中的配置别名和加载Student类的映射配置文件可以暂时忽略,因为此处不用。

运行结果:

Mybatis入门使用总结

阅读上面的代码会发现,其实Mybatis是采用配置文件的形式来配置数据库连接的信息。然后采用Reader的形式去读取配置文件,来获取连接的信息。从而交给SqlSessionFactory来建立连接。第二点就是采用ThreadLocal这么一个类来实现,在我的多线程通信的博文中说过ThreadLocal类主要解决的就是每个线程绑定自己的值,就是用来存储每个线程的私有数据。所以使用ThreadLocal就是把当前线程与SqlSession对象绑定一起了。然后作为工具类实现了一个获取连接和关闭连接的方法,便于后面使用。

3.Mybatis实现CRUD

pojo(Student):

public class Student {
private Integer id;
private String name;
private double sal;
public Student(){}
public Student(Integer id, String name, double sal) {
this.id = id;
this.name = name;
this.sal = sal;
}

  getter、setter方法......

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

<!-- namespace属性是名称空间,必须唯一 -->
<mapper namespace="studentNamespace">
<!-- resultMap:映射实体与表
type属性:表示实体全路径名
id属性:为实体与表的映射取一个唯一的编号
-->
<resultMap type="Student" id="studentMap">
<!-- id标签:映射主键属性
result标签:映射非主键属性
property属性:实体的属性名
column属性:表的字段名
-->
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sal" column="sal"/>
</resultMap>

<!-- insert标签:要书写insert这么一个语句
id属性:为insert这么一个sql语句取一个任意唯一的名字
parameterType:要执行的dao中的方法的参数,如果是类的话,那么必须使用全路径类。
-->
<insert id="add" parameterType="Student">
insert into students(id,name,sal) values(#{id},#{name},#{sal});
</insert>

<!-- 根据id查询学生类 -->
<select id="findById" parameterType="int" resultType="Student">
select id,name,sal from students where id=#{id};
</select>

<!-- 查询所有的学生类
理论上resultType要写List<Student>
但这里只需书写List中的类型即可,即只需书写Student的全路径名
-->
<select id="findAll" resultType="Student">
select * from students;
</select>

<!-- 更新学生表记录 -->
<update id="update" parameterType="Student">
update students set name=#{name},sal=#{sal} where id=#{id};
</update>

<!-- 删除学生记录 -->
<delete id="delete" parameterType="Student">
delete from students where id=#{id};
</delete>
</mapper>
解释:Mybatis采用模型对象的映射文件,作为数据库操作语句的对象。使用resultMap这个标签来封装。至于说明都在代码的注释上,如果还有不明白,那么可以看Mybatis文档给出了例子。。

由于Mybatis是一个orm框架,所以必然是作为数据库操作的一个框架。那么对应还需要dao层的代码。

dao接口:

public interface IStudentDao {

public void add(Student student) throws Exception;
public void delete(Student student) throws Exception;
public void update(Student student) throws Exception;
public Student selectOneById(int id) throws Exception;
public List<Student> selectAll() throws Exception;
}

dao实现类:

public class StudentDaoImpl implements IStudentDao{

@Override
public void add(Student student) throws Exception {
// TODO Auto-generated method stub
SqlSession sqlSession =null;
try{
sqlSession =MybatisUtil.getSqlSession();
//开启事务
//读取StudentMapper.xml映射文件中的SQL语句
sqlSession.insert("studentNamespace.add",student);
//事务提交
sqlSession.commit();
}catch(Exception e){
e.printStackTrace();
//事务回滚
sqlSession.rollback();
throw e;
}finally{
MybatisUtil.closeSqlSession();
}
}

@Override
public void delete(Student student) throws Exception {
SqlSession sqlSession =null;
try{
sqlSession =MybatisUtil.getSqlSession();
//开启事务
//读取StudentMapper.xml映射文件中的SQL语句
sqlSession.delete("studentNamespace.delete",student);
//事务提交
sqlSession.commit();
}catch(Exception e){
e.printStackTrace();
//事务回滚
sqlSession.rollback();
throw e;
}finally{
MybatisUtil.closeSqlSession();
}
}

@Override
public void update(Student student) throws Exception {
SqlSession sqlSession =null;
try{
sqlSession =MybatisUtil.getSqlSession();
sqlSession.update("studentNamespace.update",student);
sqlSession.commit();
}catch(Exception e){
e.printStackTrace();
//事务回滚
sqlSession.rollback();
throw e;
}finally{
MybatisUtil.closeSqlSession();
}

}

@Override
public Student selectOneById(int id) throws Exception {
SqlSession sqlSession =null;
try{
sqlSession =MybatisUtil.getSqlSession();
Student student =sqlSession.selectOne("studentNamespace.findById", id);
sqlSession.commit();
return student;
}catch(Exception e){
e.printStackTrace();
//事务回滚
sqlSession.rollback();
throw e;
}finally{
MybatisUtil.closeSqlSession();
}
}

@Override
public List<Student> selectAll() throws Exception {
SqlSession sqlSession =null;
try{
sqlSession =MybatisUtil.getSqlSession();
return sqlSession.selectList("studentNamespace.findAll");
}catch(Exception e){
e.printStackTrace();
//事务回滚
sqlSession.rollback();
throw e;
}finally{
MybatisUtil.closeSqlSession();
}
}
}

解释:发现获取连接和释放连接都是采用之前写的例子Mybatis工具类。然后获取到sqlSession对象。通过sqlSession做操作。对于操作方法中第一个参数的解释:名称空间.配置文件操作标签的id。这样就使sqlSession可以找到StudentsMapper对应的sql语句。而从配置文件中也可以大概分析出采用了模板方法模式。虽然crud都是一套固定的标签,然而每一个使用者用到sql语句可能会不同,由于每个人需要的查询不同,并且可以得到需要的不同查询结果。

注意:

在同样的程序中为什么我的程序却跑不起来呢。需要一点配置在Mybatis.xml总配置文件中。

   配置StudentMapper映射,让Mybatis.xml加载:

<!-- 加载映射文件 -->
<mappers>
<mapper resource="cn\spy\model\StudentMapper.xml"/>
</mappers>
细节在入门例子中有配置。

   然而mybatis.xml配置文件中使用别名的配置是为了简化开发,减少写太长的类路径。

4.Mybatis实现分页

pojo类、mybatis.xml等前面例子一样的。主要是StudentMapper.xml、dao实现类的编写。

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">

<!-- namespace属性是名称空间,必须唯一 -->
<mapper namespace="studentNamespace">
<!-- resultMap:映射实体与表
type属性:表示实体全路径名
id属性:为实体与表的映射取一个唯一的编号
-->
<resultMap type="Student" id="studentMap">
<!-- id标签:映射主键属性
result标签:映射非主键属性
property属性:实体的属性名
column属性:表的字段名
-->
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sal" column="sal"/>
</resultMap>
<!-- 分页查询学生记录 -->
    <select id="selectByPaging" parameterType="map" resultMap="studentMap">
        select id,name,sal from students limit #{pstart},#{psize};
    </select>
</mapper>

dao接口:

public interface IStudentDao {
    public List<Student> selectByPaging(int start ,int size) throws Exception;
}

dao实现类:

public class StudentDaoImpl implements IStudentDao{
@Override
    public List<Student> selectByPaging(int start ,int size) throws Exception {
        SqlSession sqlSession =null;
        try{
            sqlSession =MybatisUtil.getSqlSession();
            Map<String,Object> map =new LinkedHashMap<String,Object>();
            map.put("pstart", start);
            map.put("psize", size);
            return sqlSession.selectList("studentNamespace.selectByPaging", map);
        }catch(Exception e){
            e.printStackTrace();
            //事务回滚
            sqlSession.rollback();
            throw e;
        }finally{
            MybatisUtil.closeSqlSession();
        }
    }
}
测试:

public static void main(String[] args) throws Exception {
IStudentDao studentDao =new StudentDaoImpl();
System.out.println("-------------第一页");
        List<Student> list1 =studentDao.selectByPaging(0, 4);
        for(Student stu:list1){
            System.out.println(stu);
        }
}
结果:

Mybatis入门使用总结

数据库:

Mybatis入门使用总结

解释:Mybatis主要就是使用sql语句进行操作的。而mysql对于分页查询提供了limit关键字,方便了查询。而传入的第几条记录开始和每页显示的记录数,使用map传入。而StudentMapper.xml中使用

parameterType="map" resultMap="studentMap"
来传参和设置返回结果。

5.Mybatis实现有条件分页查询

有条件分页查询,就是使用分页查询,但是使用了条件进行过滤,而我此处玩下模糊查询做为条件。

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">

<!-- namespace属性是名称空间,必须唯一 -->
<mapper namespace="studentNamespace">
<!-- resultMap:映射实体与表
type属性:表示实体全路径名
id属性:为实体与表的映射取一个唯一的编号
-->
<resultMap type="Student" id="studentMap">
<!-- id标签:映射主键属性
result标签:映射非主键属性
property属性:实体的属性名
column属性:表的字段名
-->
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sal" column="sal"/>
</resultMap>
<!-- 有条件分页 -->
    <select id="selectByConditionalPaging" parameterType="map" resultMap="studentMap">
        select id,name,sal from students where name like #{pname} limit #{pstart},#{psize};
    </select>
</mapper> 
dao接口:

public interface IStudentDao {
public List<Student> selectByConditionalPaging(String name ,int start ,int size) throws Exception;
}
dao实现类:

public class StudentDaoImpl implements IStudentDao{
@Override
    public List<Student> selectByConditionalPaging(String name, int start,
            int size) throws Exception {
        SqlSession sqlSession =null;
        try{
            sqlSession =MybatisUtil.getSqlSession();
            Map<String,Object> map =new LinkedHashMap<String,Object>();
            map.put("pname", "%"+name+"%");
            map.put("pstart", start);
            map.put("psize", size);
            return sqlSession.selectList("studentNamespace.selectByConditionalPaging", map);
        }catch(Exception e){
            e.printStackTrace();
            //事务回滚
            sqlSession.rollback();
            throw e;
        }finally{
            MybatisUtil.closeSqlSession();
        }
    }
}
测试:

public static void main(String[] args) throws Exception {
IStudentDao studentDao =new StudentDaoImpl();
System.out.println("-------------第一页");
     List<Student> list1 =studentDao.selectByConditionalPaging("魏大勋", 0, 4);
     for(Student stu:list1){
        System.out.println(stu);
     }
}
结果:

Mybatis入门使用总结

6.Mybatis工作流程

(1)通过Reader对象读取src目录下的mybatis.xml配置文件(该文本的位置和名字可任意)

(2)通过SqlSessionFactoryBuilder对象创建SqlSessionFactory对象

(3)从当前线程中获取SqlSession对象

(4)事务开始,在mybatis中默认

(5)通过SqlSession对象读取StudentMapper.xml映射文件中的操作编号,从而读取sql语句

(6)事务提交,必写

(7)关闭SqlSession对象,并且分开当前线程与SqlSession对象,让GC尽早回收

-----------------------------------------


至于Mybatis的两个配置文件,上面都有注解就不再赘述了。