MyBatis的基础内容

本文主要介绍MyBatis的基础内容,包括基本概念、开发步骤、使用实例等。说起MyBatis,工作中做过SSH/SSM相关Web开发的或者正在学习MyBatis的人或多或少都会接触到类似“MyBatis和Hibernate有什么区别?”,“MyBatis和Hibernate哪个更好?”,“为什么Mybatis用的人越来越多?”等等…记得面试问题,区别问的最多,有次被面试官问到更喜欢用哪一个?明明已经知道这个公司介绍用的是SSM了,我答了个Hibernate,并说先用的也是Hibernate,或许初恋的感觉过于深刻吧…谁好谁差这种主观性问题,我们不争论,但是不容质疑的是两者都为企业级开发做出巨大贡献。同时,带着问题和求知欲去学习往往会让学习效率大大提高,因为许多问题在困惑你的同时,也为你指引了方向。就正如你得会用它,理解它了,才知道它在某方面为什么会不足。

MyBatis介绍
  早些时候,Apache有一个开源项目iBatis,后来改名了叫Mybatis,所以我们在网上有时候会看到一些早期的文章有时候看到iBatis,其实是同一个东西。同时,大家可以看下MyBatis源码工程结构,如下图,也能发现这个问题。

MyBatis是一个半自动-ORM-持久层框架,下面分别介绍这三个概念,如果了解的的可以直接跳过以节省时间。

首先持久层比较好理解,就是针对数据库的各种操作持久化层面,我们用jdbc也可以对数据库中表进行增删可查;WEB开发分层结构中,类似的还有业务层、控制层,MyBatis所做用的层,主要是用于与数据库打交道。

其次ORM(Object Relational Mapping,对象关系映射)是一种技术,也是思想,如果用过jdbc的原生方式操作数据的应该都知道,其中各种获取和更新的操作都已有相关的API了,但是这个过程实在太繁琐,获取连接、构造语句、发送SQL和接收数据、最后是处理数据和关闭流等等…实际的工作开发中,显然不太适用。也许是有人想到,最麻烦的地方在于获取数据后的处理过程,为了简化这一过程,以Java中面向对象的思维构造了这一个ORM关系模型,即每张数据表对应一个Java类,数据表中每一条记录分别对应Java类的一个实体对象,数据表中每个字段对应Java类中的一个属性,这样一来Java中一切皆对象,数据库里的东西既然已经对应映射到Java概念中来,我们再用面向对象的思维去操作数据库,就大大简化了开发流程。

最后,解释半自动,既然有半自动,应该就有全自动,例如Hibernate就是一个全自动的ORM持久层框架,它在建立数据库和bean对象关系映射模型的同时,提供的api还会帮助我们自动生成和发送SQL语句去操作数据库,而MyBatis略有不同,它也建立了对象关系映射模型,但是并不会帮助我们生成SQL语句,需要我们自己写SQL语句,不少人可能会觉得别人都可以帮你自动生成了这还要自己写,不是没事找事吗?但是恰恰相反,很多人因为这点喜欢上了MyBatis,灵活且透明,自己动手不解释。

MyBatis重要对象
  关于MyBatis的学习使用过程中,依次要注意的四个对象有SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession、Mapper实例。

1.SqlSessionFactoryBuilder

SqlSessionFactoryBuilder是一个类,里面定义许多重载的build方法,通过build方法可以获取SqlSessionFactory对象,即SqlSession工厂实例

2.SqlSessionFactory

SqlSessionFactory是一个接口,看名字应该能明白是SqlSession工厂,里面定义了许多重载的openSession方法,用于获取SqlSession对象

3.SqlSession

SqlSession是一个很关键的接口,通过它我们可以执行发送SQL语句、获得Mapper实例等等。以它的第一个方法为例, T selectOne(String statement); 方法名很容易理解,获取数据表的一条记录(在Java中对应返回一个实体类对象),前面的泛型对应的就是实体类的类型,关于String类型的参数statement,用过原生的JDBC操作数据库的应该不会陌生,在使用JDBC过程中,有个Statement对象,通过该对象的类似 ResultSet executeQuery(String sql) throws SQLException; 等方法可以发送SQL语句,方法里的字符串类型参数 sql 就是我们要发送的sql语句,而前面的String statement 同样也是代表我们的sql语句。总的来说,selectOne中的statement代表sql语句,JDBC中的statement是能发送sql语句的对象实例,不可混淆。

4.Mapper实例

Mapper实例就是我们在dao层定义的定义的接口实例,我们在service层中注入dao对象时关联的是该接口名,而实际上我们拿到了该接口实例也就是Mapper实例。而我们在web开发过程中,持久层的相关方法都定义在Mapper接口中,所以四个对象里我们在前面环境搭建篇比较容易发现的也就是这个Mapper实例所属接口,即PersonMappr接口。Mapper实例可以通过SqlSession的getMapper方法获得。

MyBatis配置文件

以上为MyBatis配置文件下节点的结构分布图,熟悉DTD的根据org/apache/ibatis/builder/xml下的约束文件mybatis-*-config.dtd也可以获取XML规范。

environment(环境)

在开发中,我们要连接到数据库,往往都需要配置一个数据源,其中包括数据库url参数,用户名和密码等等,另外还有事事务管理器配置。MyBatis中也不例外,在这里针对一个数据库的连接,有一个environment(环境)与之对应,如果有多个数据库,我们可以在environments下定义多个environment。environment下面通过dataSource和transactionManager的property属性进行数据源和事务管理器配置。

typeAliases(类型命名)

这个是开发中很实用的配置,前面配置篇中mybatis-config.xml中的,给类绑定别名,然后在其他地方引用时可以不用写类的全名(类似com.xxx.Xxx形式),直接写别名即可,例如后面personMapper.xml映射文件中,这里的person别名就代表该类了,如果没有前面的别名绑定,我们在所有需要类型type指定com.mmm.pojo.Person的时候,都需要写全名。另外MyBatis中本身已经绑定了许多类似的别名,在Configuration类的构造中已经预先注册绑定了相关别名,这也是我们在用Spring集成开发的配置文件中那些特殊别名能得到解析的关键所在,如下所示

复制代码
public Configuration() {
   
typeAliasRegistry.registerAlias(“JDBC”, JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias(“MANAGED”, ManagedTransactionFactory.class);
  
typeAliasRegistry.registerAlias(“JNDI”, JndiDataSourceFactory.class);
typeAliasRegistry.registerAlias(“POOLED”, PooledDataSourceFactory.class);
typeAliasRegistry.registerAlias(“UNPOOLED”, UnpooledDataSourceFactory.class);
   
typeAliasRegistry.registerAlias(“PERPETUAL”, PerpetualCache.class);
typeAliasRegistry.registerAlias(“FIFO”, FifoCache.class);
typeAliasRegistry.registerAlias(“LRU”, LruCache.class);
typeAliasRegistry.registerAlias(“SOFT”, SoftCache.class);
typeAliasRegistry.registerAlias(“WEAK”, WeakCache.class);
  
typeAliasRegistry.registerAlias(“DB_VENDOR”, VendorDatabaseIdProvider.class);

typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);

typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);

typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);

languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
languageRegistry.register(RawLanguageDriver.class);

}
复制代码
  mappers(映射器)

  以上即为一个映射器配置样式,通过该配置,Mybatis会找到相应的SQL映射文件(前面环境搭建篇中为personMapper.xml),下面详细介绍SQL映射文件。

MyBatis真正的力量
  The true power of MyBatis is in the Mapped Statements(MyBatis真正的力量就在SQL映射语句里)。这是MyBatis对SQL映射文件作介绍的第一句话,足以体现其重要性,前面说到的半自动的MyBatis需要自己写SQL语句,这个写SQL语句的地方就在这里。

根节点mapper有一个属性namespace(命名空间),对应的是Mapper接口的全名,通过这个属性值的设置,MyBatis才能找到该SQL映射文件对象Mapper接口,从而构造相应的Mapper实例对象。

以上为MyBatis的SQL映射xml文件的元素结构,子节点中还有一个parameterMap,不过已经被废弃了,就没画上去。前面四个,看单词意思,应该不难理解,分别用于定义增删改查SQL语句。下面以查询为例

select * from `TBL_PERSON` where id = #{id}   上面select节点中id为该节点的唯一标识,与其它节点区分,另一方面,id名对应我们的Mapper接口中的方法名,在这里对应PersonMapper的如下方法:

//根据主键id查找Person对象
Person selectById(String id);
  由于是查询,会有返回数据内容,基于ORM思想,这里的T_PERSON表返回记录有一个实体类与之对应,那么具体对应哪个实体类怎么指定?这里的resultType即指定返回数据对应类型,并且用到了别名,所以这里其实就是指定了com.mmm.pojo.Person类作为对应实体类。另外还有一种resultMap定义方式,也可以指定返回类型,两者不能同时使用,下面会具体讲到。如果方法没有返回值,也可以不指定类型。

节点中的语句即为该方法对应的SQL语句,这里的#{id}表示参数,对应PersonMapper接口中对应方法的参数String id。

另外三种类似,不过要注意,作为插入节点,有几个特殊属性,useGeneratedKeys、keyProperty、keyColumn,这三个属性都是特有的,也仅对其有效,keyProperty属性指定数据表主键值对应的实体类属性,这里为Person类中的id;keyColumn属性指定数据表主键字段名,这里为id;useGeneratedKeys指定是否使用数据表主键策略生成的主键值,例如在Mysql中主键可以设置自增,然后我们在插入记录(或者说是写SQL语句)时,即使不指定主键值,插入也会成功,并且主键会自动赋值。为了以示区别,文中构建示例我会使用MySQL的自增主键,而不是之前的随机字符串作为主键。

被用来定义可重用的SQL代码段,可以包含在其他语句中。

再来看,之前的Person实例中,数据表的字段名和实体类属性名都是一样的,id,name,gender。如果不一样的话,我们再采用之前的写法就会有问题了,resultMap给我们提供了解决办法,下面我们通过完整构建一个Mybatis环境来演示整体内容。

MyBatis实践
  这里我们单独讲Mybatis,并未使用Spring集成环境,也并未用到web层的Spring MVC,所以不需要构建web项目。所以首先通过maven新建一个java项目,pom.xml依赖可以参考前面的SSM环境搭建,最后项目结构大致如下图所示

数据库中准备一张员工表TBL_EMP,三个字段:主键id自增,姓名emp_name,性别emp_gender,插入若干数据,如下图

实体类(Emp.java)
复制代码
package com.mmm.pojo;
//员工实体类
public class Emp {
private Integer id; //主鍵
private String name; //员工姓名
private String gender; //员工性别

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 getGender() {
    return gender;
}
public void setGender(String gender) {
    this.gender = gender;
}

}
复制代码
  配置文件(mybatis-config.xml)
复制代码

<?xml version="1.0" encoding="UTF-8"?> 复制代码   Mapper接口(EmpMapper.java) 复制代码 package com.mmm.mapper;

import java.util.List;

import com.mmm.pojo.Emp;

public interface EmpMapper {

//新增一个Emp对象
void insert(Emp p);

//根据主键id删除Emp对象
void deleteById(Integer id);

//修改一个Emp对象
void update(Emp p);

//根据主键id查找Emp对象
Emp selectById(Integer id);

//查找所有Emp对象,返回集合类型
List<Emp> selectAll();

}
复制代码
  SQL映射文件(EmpMapper.xml)
复制代码

<?xml version="1.0" encoding="UTF-8"?>
<!-- resultMap定义,property对应实体类中属性,column对应数据表字段名 -->
<resultMap type="emp" id="empResultMap" >
    <id property="id" column="id"></id>
    <result property="name" column="emp_name"></result>
    <result property="gender" column="emp_gender"></result>
</resultMap>

<!-- 新增一条记录,这里并未在SQL语句中设置主键id值 -->
<insert id="insert" parameterType="emp" useGeneratedKeys="true" keyProperty="id" keyColumn="id"  >
    insert into `TBL_EMP`(emp_name,emp_gender) values (#{name},#{gender})
</insert>

<!-- 删除一条记录 -->
<delete id="deleteById">
    delete from `TBL_EMP` where id = #{id}
</delete>

<!-- 更新一条记录 -->
<update id="update" parameterType="EMP">
    update `TBL_EMP` set emp_name = #{name}, emp_gender = #{gender}
</update>

<!-- 查找所有记录 -->
<select id="selectAll" resultMap="empResultMap">
    select * from `TBL_EMP`
</select>

<!-- 根据主键id查找记录 -->
<select id="selectById" resultMap="empResultMap">
    select * from `TBL_EMP` where id = #{id}
</select>
复制代码   测试(TestMyBatis.java) 复制代码 package com.mmm.test;

import java.io.IOException;
import java.io.Reader;
import java.util.List;

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 org.junit.Test;

import com.mmm.mapper.EmpMapper;
import com.mmm.pojo.Emp;

public class TestMyBatis {

@Test
public void testCore() throws IOException {
    //直接实例SqlSessionFactoryBuilder对象
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    //MyBatis配置文件路径
    String path = "mybatis-config.xml";
    //通过路径获取输入流
    Reader reader = Resources.getResourceAsReader(path);
    //通过reader构建sessionFactory
    SqlSessionFactory sessionFactory = builder.build(reader);
    //获取SqlSession对象
    SqlSession sqlSession = sessionFactory.openSession();
    //获取Mapper实例
    EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    
    //获取所有记录并遍历展示
    List<Emp> list = mapper.selectAll();
    for(Emp emp:list) {
        System.out.println("姓名:"+emp.getName()+",性别:"+emp.getGender());
    }
    
}

}
复制代码
  运行程序成功,结果如下

小结
  本文主要介绍了单独以MyBatis构建数据库访问程序的方法步骤,涉及的都是MyBatis基础和核心的内容,数据库也是针对的单表操作。MyBatis的关联查询、动态SQL、事务管理和Spring集成MyBatis等内容准备梳理一番了之后写出来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值