当前位置: 首页 > java>阅读正文

java持久层框架-Mybatis入门参考

2022.1.8 朱丰华 2019 次 留下评论 8210字

mybatis是一款优秀的持久层框架,它是半自动的、轻量级java框架,官方文档:mybatis-3(Spring整合可参考:mybatis-spring

它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

mybatis是Apache开源的项目,原名ibatis,在2010年从apache software foundation迁移到google code,在2013年迁移到github。在github上不但能搜索到mybatis源码,还能找到一些对应的mybatis翻译、插件。

  • 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
  • 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
  • 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
  • 提供映射标签,支持对象与数据库的orm字段关系映射
  • 提供对象关系映射标签,支持对象关系组建维护
  • 提供xml标签,支持编写动态sql。

Mybatis对新手来说,最强大的功能是动态sql(因为新手很难封装如此简化的工具)

Mybatis在设计方面:

  • 使用XML:能实现解耦,但使用成本高
  • 使用注解:并不能解耦,但能快速开发

此外,它非常灵活且易于扩展,它有很多插件,或者我们可以自己做插件,灵活扩展才是它真正的灵魂,也可以预见短时间内很难有好的框架取代它。

综上,Mybatis并非处处完美,相对也有缺点,但使用人数很多、公司使用的比较多,另外我们可以从Mybatis中吸收它设计的好的地方以便我们设计出更棒的框架,以上是我们为什么需要学习Mybatis的原因。

第一个mybatis项目

注释:第一个程序可参考mybatis官方文档:Mybatis-getting-start,mybatis不推荐使用注解,本程序基于xml。

首先,你需要创建数据库,本文使用mysql5.7。

create database mybatis;
use mybatis;
create table if not exists user(
    id int(20) primary key auto_increment,
    name varchar(30) default null,
    pwd varchar(30) default null
)engine innodb default character set utf8;
insert into user(name,pwd) values('张三','123456'),('李四','123'),('王五','666');

select * from user;

使用maven创建项目时导入mybatis坐标以及mysql坐标:

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.5.2</version>
</dependency>
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.6</version>
</dependency>

此外,因为maven是约定大于配置,如果你想在java目录使用resources,需要编写以下build规则

<build>
  <resources>
    <resource>
      <directory>src/main/resources</directory>
      <includes>
        <include>**/*.properties</include>
        <include>**/*.xml</include>
      </includes>
      <filtering>true</filtering>
    </resource>
    <resource>
      <directory>src/main/java</directory>
      <includes>
        <include>**/*.properties</include>
        <include>**/*.xml</include>
      </includes>
      <filtering>true</filtering>
    </resource>
  </resources>
</build>

核心配置文件

核心配置文件,也叫主配置文件,必须使用xml文件配置,通常在resource目录新建一个名为mybatis-config.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>
    <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://localhost/mybatis?useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="mybatis"/>
                <property name="password" value="YOUR_PASSWORD"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
</configuration>

创建一个MybatisUtil工具类,以快速获取SqlSession

public class MybatisUtil {

    static SqlSessionFactory sqlSessionFactory;

    static{
        String resource = "mybatis-config.xml";
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession(true);  // 如果缺省参数,否则默认false,执行增、删、改后不会自动提交
    }
}

创建User实体类,主要注意,必须符合ORM规则,类属性和表字段一一对应

public class User {
    private int id;
    private String name;
    private String pwd;

    public User() {
    }

    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }


    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}

配置mapper

编写userMapper类,此类相当于jdbc的dao类,mybatis中一般不叫dao

import java.util.List;

public interface UserMapper {
    List<User> getUser();
}

编写userMapper.xml,此文件相当于jdbc的daoImpl(注意resultType,因为是集合类型,这里返回集合包装的类型,解释请参阅官方文档:mybatis – MyBatis 3 | XML 映射器

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="mapper.UserMapper">
    <select id="getUser" resultType="domain.User">
        select * from user;
    </select>
</mapper>

编写测试类

public class Test {

    public static void main(String[] args) {
        SqlSession sqlSession = MybatisUtil.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = mapper.getUser();
        for (User user : users) {
            System.out.println(user);
        }
        sqlSession.close();
    }
}

运行程序,得到如下结果:

User{id=1, name='张三', pwd='123456'}
User{id=2, name='李四', pwd='123'}
User{id=3, name='王五', pwd='666'}

可能会遇到的错误:

  1. mapper未注册,每一个mapper.xml需要在主配置文件中注册
  2. 绑定接口错误,mapper.xml的namespace需要正确绑定mapper类
  3. 方法名不对,mapper.xml的select的id与方法名要匹配
  4. 返回类型不对,mapper.xml的resultType需要指定返回值类型
  5. maven导出资源问题,在java路径下的资源需要手动编写build规则

mybatis增删改查

以下对mapper的增删该查进行详细说明,此部分对应于官方文档:xml映射文件

select语句

在mapper类中,添加一个方法,通过ID查询用户

User getUserById(int id);

在mapper.xml中,添加一个select标签,内容如下:

<select id="getUserById" parameterType="int" resultType="domain.User">
    select * from user where id = #{id};
</select>

这里的#{id}表示预处理语句参数,parameterType表示参数的类型

在test中,通过mapper对象,使用getUserById方法查询用户

System.out.println("********");
User userById = mapper.getUserById(2);
System.out.println(userById);

得到如下结果:

********
User{id=2, name='李四', pwd='123'}

insert, update 和 delete

与select不同的是,insert,update 和 delete必须提交事务。

数据变更语句 insert,update 和 delete 的实现非常接近,以下以insert示例。

在mapper类增加一个方法,使用int作为返回值,作为操作结果的判断标志

int addUser(User user);

在mapper.xml中,添加一个insert标签,内容如下:(注意name, pwd是怎么来的,它会自动检测参数实体类中对应属性)

<insert id="addUser" parameterType="domain.User">
    insert into user(name,pwd) values(#{name},#{pwd});
</insert>

接着,在test中,使用mapper对象执行addUser方法

int addResult = mapper.addUser(new User(1, "哈哈", "123"));
if(addResult>0){
    System.out.println("提交成功");
    sqlSession.commit();
}
System.out.println("*********");

注意,你必须提交事务,否则不生效。

使用注解开发

在官方文档中并没有关于注解开发的案例,感兴趣的可以在其源码中找到所有的注解(大部分注解位于org.apache.ibatis.annotations包下),以下均是一些经验与积累。

总体来说,这些常用注解分为三大类:SQL语句映射,结果集映射和关系映射。

基本的增删改查

使用注解开发比XML更简单,一般只需要以下三个步骤

一:在Mybatis主配置文件中映射指定的接口类

上面的例子我们已经映射了一个XML,在mappers标签中添加一个类似的标签,使用class属性指定一接口,这样该接口才会被mybatis调用

    <mappers>
        <mapper resource="xml/UserMapper.xml"/>
        <mapper class="anno.UserMapper2"/>
    </mappers>

二、编写该UserMapper2接口

public interface UserMapper2 {

    @Select("select * from user")
    List<User> getUser();

    @Update("update user set name=#{name},pwd=#{pwd} where id=#{id}")
    int updateUser(User user);

    @Delete("delete from user where id=#{id}")
    int deleteUser(int id);

    @Insert("insert into user(id,name,pwd) values(#{id},#{name},#{pwd})")
    int addUser(User user);
}

在接口对应方法中编写注解即可,不再需要编写XML。

三、测试调用:

public class TestAnno {

    SqlSession sqlSession = MybatisUtil.getSqlSession();
    UserMapper2 mapper = sqlSession.getMapper(UserMapper2.class);


    // 测试查询
    @org.junit.jupiter.api.Test
    public void testSelect(){

        List<User> users = mapper.getUser();
        for (User user : users) {
            System.out.println(user);
        }
        sqlSession.close();
    }

    // 测试更新
    @org.junit.jupiter.api.Test
    public void testUpdate(){

        int i = mapper.updateUser(new User(7,"李2","222"));
        System.out.println(i==0?"失败":"成功");
        sqlSession.close();
    }

    // 测试删除
    @org.junit.jupiter.api.Test
    public void testDelete(){
        int i = mapper.deleteUser(9);
        System.out.println(i==0?"失败":"成功");
        sqlSession.close();
    }

    // 新增用户
    @org.junit.jupiter.api.Test
    public void testInsert(){
        int i = mapper.addUser(new User(10,"张","1111"));
        System.out.println(i==0?"失败":"成功");
        sqlSession.close();
    }
}

SQL语句映射

SQL语句映射,用于编写SQL使用

@Param注解

此注解用于标识接口中传递的参数别名。

当接口中仅有一个数据时可以不使用此注解,比如 selectById(int id),那么在mapper中可以直接使用#{id}

而如果是 insert(String name, String pwd), 则在mapper中就无法直接使用#{name}和#{pwd},此时默认是#{param1}和#{param2}(或arg0和arg1),也就是说默认会根据顺序解析,可以使用arg或者param标识。

使用@param后,则可以指定参数别名传递给mapper,例如

public interface UserMapper {
    List<User> select(@Param("name") String name,@Param("age") byte age);
}

如果不使用这种方式,可以使用对象或者map封装后,此时只需要传递一个参数。

使用对象的方式前面已经进行介绍,下面介绍map传递参数:

首先创建啊一个hashMap对象,泛型为<String, Object>,其中的key就是可以被识别的名称,而value就是传递的值

在接口中传递此参数后,需要在mapper中指定parameterType=map,例如以下例子:

//使用Map传参添加用户
int addUser2(Map<String,Object> map);
//使用Map传参修改用户信息
int updateUser2(Map<String,Object> map);
<insert id="addUser2" parameterType="map">
    insert into mybatis.user (name, pwd) values(#{userName},#{passWorld}) ;
</insert>

<update id="updateUser2" parameterType="map">
    update mybatis.user set name=#{userName},pwd=#{password} where id=#{userId} ;
</update>

增删改查注解

最基本的4个注解

注解描述
@Insert实现新增功能
@Select实现查询功能
@Update实现更新功能
@Delete实现删除功能

附加手册

typeAliases标签:指定一个类的别名,不区分大小写

package标签:指定一个包的别名,并且该包下所有类名均为其别名

properties标签:可以直接指定配置信息,或者使用resource属性指定外部properties文件地址,也可以使用url属性指定file协议地址。

本篇完,还有疑问?留下评论吧

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注