Mybatis入门

2022-07-10 13:25:56

MyBatis简介

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

介绍接不多说了,下面开始写代码

准备事项

开发工具:IDEA, Idea中需要安装插件MyBatis plugin来支持开发MyBatis,这个插件非常的有用,安装和具体的作用,大家百度哈,这里只将mybatis

新建工程

在idea中新建一个简单的java工程,创建成功后的目录如下:

然后准备mybatis的包和连接数据库所用的包

mybatis的包,大家可以去http://github.com/mybatis/mybatis-3/releases下载,还有一个大家需要到网上下载,我把这两个包上传到CSDN上了,大家可以去下CSDN地址百度云地址,提取码dbjv

在工程下面新建一个lib目录,将这个两个包放在lib目录下面

这里还没有结束,还要在项目中显示报这两个包导入到依赖中去,点击file ->project structure->Modules->Dependecies,然后点击+号,选择第一个

创建数据库和表

在创建实体类前,我们先创建表,创建一个test数据库,再创建一个user表,并插入两行数据

DROP DATABASE IF EXISTS test;
CREATE DATABASE test DEFAULT CHARACTER SET utf8;

use test;
CREATE TABLE user(
  id int(11) NOT NULL AUTO_INCREMENT,
  user_name varchar(255) NOT NULL,
  password varchar(255) NOT NULL,
  age int(11) NOT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO user VALUES(1,'guolin','123456',18);
INSERT INTO user VALUES(2,'love','123456',18);

创建实体类

在src下创建一个dto的包,并dto包下创建一个User的实体类

package dto;

public class User {
    private Integer id;
    private String userName;
    private String password;
    private Integer age;

    /*setter and getter*/
}

然后在src下面创建一个resources的包,并将其设置项目resources模块,具体操作,单击file -> project structure -> Modules:当resources文件夹右下角出现一个黄色小图标时就ok

将resources包设置成项目的resources模块后,接下来的我们的配置文件,以及实体类对应的xml文件都放在它下面

创建配置文件mybatis.xml

在resources下面新建一个mybatis的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>
    <!-- 驼峰转换 -->
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true" />
    </settings>
    <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:3306/test"/>
                <property name="username" value="root"/>
                <property name="password" value="admin"/>
            </dataSource>
        </environment>
    </environments>
    
</configuration>

配置User.xml

resources下新建一个mapper文件,然后在mapper下新建一个User.xml,项目中与实体类映射的xml我们都放到mapper下

<?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="dto">
    <select id="listUser" resultType="dto.User">
      select * from user;
    </select>
</mapper>

这里namespace为dto,我们这里还没有使用接口绑定,所以指向的是我们的实体类的包,这里引用一下官网的解释

然后我们写了一个select语句,id为listUser,resultType表示返回类型,我们这里是User类型,然后我们要到mybatis中配置一下,这样mybatis才能找到我们user.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>
    <!-- 驼峰转换 -->
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true" />
    </settings>
    <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:3306/test"/>
                <property name="username" value="root"/>
                <property name="password" value="admin"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 映射文件 -->
    <mappers>
        <mapper resource="mapper/User.xml"/>
    </mappers>
</configuration>

测试类

在src下新建一个test包,在包下新建一个Test类

package test;

import dto.User;
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 java.io.InputStream;
import java.util.List;

public class Test {
    public static void main(String[] args) throws Exception{
        // 根据 mybatis-config.xml 配置的信息得到 sqlSessionFactory
        String resource = "mybatis.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 然后根据 sqlSessionFactory 得到 session
        SqlSession session = sqlSessionFactory.openSession();
        // 最后通过 session 的 selectList() 方法调用 sql 语句 listStudent
        List<User> listStudent = session.selectList("listUser");
        for (User user : listStudent) {
            System.out.println("ID:" + user.getId() + ",NAME:" + user.getUserName());
        }
    }
}

运行结果

增删改查

在User.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="dto">
    <select id="listUser" resultType="dto.User">
      select * from user;
    </select>

    <insert id="addUser" parameterType="dto.User">
        insert into user (id, user_name,password,age)
        values(#{id},#{userName},#{password},#{age})
    </insert>

    <delete id="deleteUser" parameterType="dto.User">
        delete from user where id = #{id}
    </delete>

    <update id="updateUser" parameterType="dto.User">
        update user set user_name = #{userName},password = #{password} where id = #{id}
    </update>

    <select id="selectUserById" parameterType="java.lang.Integer" resultType="dto.User">
        select * from user where id = #{id}
    </select>
</mapper>

测试类

package test;

import dto.User;
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 java.io.InputStream;
import java.util.List;

public class Test {
    public static void main(String[] args) throws Exception{
        // 根据 mybatis-config.xml 配置的信息得到 sqlSessionFactory
        String resource = "mybatis.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 然后根据 sqlSessionFactory 得到 session
        SqlSession session = sqlSessionFactory.openSession();

        //增加语句
        User user1 = new User();
        user1.setId(3);
        user1.setUserName("xuchao");
        user1.setPassword("123456");
        user1.setAge(18);
        session.insert("addUser",user1);

        //删除语句
        User user2 = new User();
        user1.setId(1);
        session.delete("deleteUser",user2);

        //根据id查询单个user信息
        User user3 = session.selectOne("selectUserById",2);

        //更新语句
        user3.setUserName("chenzixin");
        user3.setPassword("1997");
        session.update("updateUser",user3);

        // 最后通过 session 的 selectList() 方法调用 sql 语句 listStudent
        List<User> listStudent = session.selectList("listUser");
        for (User user : listStudent) {
            System.out.println("ID:" + user.getId() + ",NAME:" + user.getUserName() + ",PASSWOED:" + user.getPassword());
        }
        session.commit(); //提交修改
        session.close();  //关闭
    }
}

新增一个id为3的user,然后删除id为1的用户,根据id查询为2的用户,最后修改用户2的信息,运行结果如下:

MyBatis高级映射

一对一查询,首先我们将user的数据全部删除,然后再将创建一张card表,并重新在user表中插入两条数据,card表也插入两条数据

use test;

create table card(
    id int(11) NOT NULL auto_increment,
    id_card int(11) NOT NULL,
    primary key(id)

)ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO user VALUES(1,'guolin','123456',18);
INSERT INTO user VALUES(2,'chenzixin','123456',18);

INSERT INTO card VALUES(1,1996);
INSERT INTO card VALUES(2,1997);

这里的user中的id与card中id是对应的,没有再设置外键,下面来看一下我们的sql语句

使用resultType

mybatis有两种属性来表示返回类型resultType和resultMap,我们先来看第一种

resultType返回期望类型的类的完全限定名或别名,我们要新建一个java实体类来映射我们上述的一对一的结果

在dto包下面新建一个OneToOne类

package dto;

public class OneToOne {
    private Integer id;
    private String userName;
    private String password;
    private Integer age;
    private Integer idCard;
    
    /* setter and getter */
}

在上面的User.xml中增加如下的<select>类型的查询语句

<select id="findByIdCard" parameterType="java.lang.Integer" resultType="dto.OneToOne">
        select
	      user.*,
          card.*
        from
	      user,card
        where user.id = card.id and card.id_card = #{v};
</select>

测试类

package test;

import dto.OneToOne;
import dto.User;
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 java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Test {
    public static void main(String[] args) throws Exception{
        // 根据 mybatis-config.xml 配置的信息得到 sqlSessionFactory
        String resource = "mybatis.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 然后根据 sqlSessionFactory 得到 session
        SqlSession session = sqlSessionFactory.openSession();

        OneToOne one = session.selectOne("findByIdCard",1997);
        System.out.println(one);

        session.commit(); //提交修改
        session.close();  //关闭
    }
}

运行结果

上面打印使用log4j打印出了sql,大家可以配置一下,首先在lib目录下导入log4j-1.2.17.jar(这里是我使用的版本号,大家也可以使用别的版本)的包,然后在src新建log4j.properties配置文件,并输入一下内容:

log4j.rootLogger=DEBUG, stdout 
log4j.appender.stdout=org.apache.log4j.ConsoleAppender 
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 
log4j.appender.stdout.layout.ConversionPattern=%d [%-5p] %c - %m%n
#show sql
log4j.logger.java.sql.ResultSet=INFO  
log4j.logger.org.apache=INFO  
log4j.logger.java.sql.Connection=DEBUG  
log4j.logger.java.sql.Statement=DEBUG  
log4j.logger.java.sql.PreparedStatement=DEBUG

使用resultMap

先来创建card表的实体类,dto包中新建Card类

package dto;

public class Card {
    private Integer id;
    private Integer idCard;
    private User user;   //引入一个User对象

    /* seeter and getter */
   
}

然后我们再新建一个Card.xml,同样是放在mapper目录下,使用resultMap来实现上诉例子

<?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="dto">
    <resultMap id="resultByCard" type="dto.Card">
        <id property="id" column="id"/>
        <result property="idCard" column="id_card"/>
        <association property="user" javaType="dto.User">
            <id property="id" column="id"/>
            <result property="userName" column="user_name"/>
            <result property="password" column="password"/>
            <result property="age" column="age"/>
        </association>
    </resultMap>
    
    <select id="selectByCard" parameterType="java.lang.Integer" resultMap="resultByCard">
      select
	      user.*,
           card.*
        from
	      user,card
        where user.id = card.id and card.id_card = #{v};
    </select>
</mapper>

这里需要在mybatis.xml中配置一下,不然mybatis就无法找到我们这些映射的文件

    <!-- 映射文件 -->
    <mappers>
        <mapper resource="mapper/User.xml"/>
        <mapper resource="mapper/Card.xml"/>
    </mappers>

测试类

package test;

import dto.Card;
import dto.OneToOne;
import dto.User;
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 java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Test {
    public static void main(String[] args) throws Exception{
        // 根据 mybatis-config.xml 配置的信息得到 sqlSessionFactory
        String resource = "mybatis.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 然后根据 sqlSessionFactory 得到 session
        SqlSession session = sqlSessionFactory.openSession();

        Card one = session.selectOne("selectByCard",1997);
        System.out.println(one);

        session.commit(); //提交修改
        session.close();  //关闭
    }
}

运行结果

这里查询一个idCard为1997的用户信息,如何想的上面这个输出值,Card和User类需要添加toString()方法,否者你得到只会是类在jvm中的地址串

一对多映射

下面我们来看看一对多映射,这里我们再重新建两张表,class表和student表,在class表中只插入条数据,student中插入两条

use test;

CREATE TABLE class(
  id int(11) NOT NULL AUTO_INCREMENT,
  name varchar(255) NOT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE student(
  id int(11) NOT NULL AUTO_INCREMENT,
  name varchar(255) NOT NULL,
  class_id int(11) NOT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


INSERT INTO class VALUES(1,'一班');

INSERT INTO student VALUES(1,'guolin',1);
INSERT INTO student VALUES(2,'chenzixin',1)

然后来看一下我们这次的sql语句

实体类

创建实体类Class1和Student,还是位于dto包下,因为Class是java中的关键字,所以我们用Class1

package dto;

import java.util.List;

public class Class1 {
    private Integer id;
    private String name;
    List<Student> list; 

    /* setter and getter */
}


package dto;

public class Student {
    private Integer id;
    private String name;
    private Integer classId;
    
    /* setter and getter */
}

上面Class1中引用了一个包含Student对象的list对象,表明一个班中包含哪些学生,下面创建Class1.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="dto">
    <resultMap id="resultByClass1" type="dto.Class1">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <collection property="list" ofType="dto.Student">
            <id property="id" column="id"/>
            <result property="name" column="name"/>
            <result property="classId" column="class_id"/>
        </collection>
    </resultMap>

    <select id="selectByClass1" parameterType="java.lang.Integer" resultMap="resultByClass1">
      select
	class.*,
        student.*
      from
	    class,student
      where class.id = student.class_id and class.id= #{parameter};
    </select>
</mapper>

测试类

package test;

import dto.*;
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 java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Test {
    public static void main(String[] args) throws Exception{
        // 根据 mybatis-config.xml 配置的信息得到 sqlSessionFactory
        String resource = "mybatis.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 然后根据 sqlSessionFactory 得到 session
        SqlSession session = sqlSessionFactory.openSession();

        Class1 one = session.selectOne("selectByClass1",1);
        System.out.println(one);
        
        session.commit(); //提交修改
        session.close();  //关闭
    }
}

运行结果

这里的结果有问题,list中应该有两条数据,Total也打印的是2,证明应该有两条,还有就是list中的name应该是student的名字,这里看上去被class的name覆盖了。百度后发现原因是由于class中的name属性覆盖了student中的name属性,至于为什么明明查出来两条数据,最后只打印一条的原因是因为class表和student表的id相同导致。

具体原因请参见此博客

下面我们来修改,修改Class1.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="dto">
    <resultMap id="resultByClass1" type="dto.Class1">
        <id property="id" column="c_id"/>
        <result property="name" column="s_name"/>
        <collection property="list" ofType="dto.Student">
            <id property="id" column="s_id"/>
            <result property="name" column="s_name"/>
            <result property="classId" column="class_id"/>
        </collection>
    </resultMap>

    <select id="selectByClass1" parameterType="java.lang.Integer" resultMap="resultByClass1">
        select
            c.id as c_id,
            c.name as c_name,
            s.id as s_id,
            s.name as s_name,
            s.class_id
        from
            class c,student s
        where c.id = s.class_id and c.id= 1;
    </select>
</mapper>

这里我们为class和student分别取了别分,其中id和那么字段也取了别名,同时resultMap中的column也要相应修改

测试类不改,再次运行

结果正确,list中两条数据,并且name属性也没有被覆盖

多对多映射

  • 作者:GL60708
  • 原文链接:https://blog.csdn.net/GL60708/article/details/89844085
    更新时间:2022-07-10 13:25:56