上一篇文章介绍了JDBC的基本使用,虽然改进写了工具类,但代码还是很多,开发效率低,自己还得注意Connection、Statement、PreparedStatement、ResultSet对象的创建和销毁,得到的结果集还需要自己封装处理,比较麻烦,业务代码和数据库操作混在一起,耦合度高。鉴于以上缺点,大牛们开发了Mybatis框架来解决这些问题。Mybatis框架就是一个封装好的JDBC,搬砖人只需要专注于写sql即可操作数据库。

官网对MyBatis的定义如下:

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

还是先从一个例子来入门Mybatis。同样,需要的依赖导入:

<dependencies>        <dependency>            <groupId>org.mybatisgroupId>            <artifactId>mybatisartifactId>            <version>3.5.1version>        dependency>        <dependency>            <groupId>mysqlgroupId>            <artifactId>mysql-connector-javaartifactId>            <version>5.1.47version>        dependency>        <dependency>            <groupId>junitgroupId>            <artifactId>junitartifactId>            <version>4.11version>            <scope>testscope>        dependency>    dependencies>    <build>        <resources>            <resource>                <directory>src/main/javadirectory>                <includes>                    <include>**/*.propertiesinclude>                    <include>**/*.xmlinclude>                includes>                <filtering>falsefiltering>            resource>            <resource>                <directory>src/main/resourcesdirectory>                <includes>                    <include>**/*.propertiesinclude>                    <include>**/*.xmlinclude>                includes>                <filtering>falsefiltering>            resource>        resources>    build>

建表如下:

查询返回的resulttype是int resulttype返回类型_查询返回的resulttype是int

1.建User表,建立与user表的映射关系。

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 + '\'' +                '}';    }}

2.编写UserDao接口,用来编写操作数据库的方法

public interface UserDao {    ListgetUserList();}

3.编写UserMapper.xml,sql映射文件,编写与UserDao接口中的方法对应的sql语句

<?xml version="1.0" encoding="UTF-8" ?>/span>        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"        "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.zhu.dao.UserDao">    <select id="getUserList" resultType="com.zhu.pojo.User">    select * from user;  select>mapper>

4.编写主配置文件mybatis-config.xml,用来连接数据库以及指定mapper文件的位置

<?xml version="1.0" encoding="UTF-8" ?>/span>        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:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/>                <property name="username" value="root"/>                <property name="password" value="root"/>            dataSource>        environment>    environments>    <mappers>        <mapper resource="com/zhu/dao/UserMapper.xml"/>    mappers>configuration>

5.测试

@Testpublic void test1()      //1.读取配置文件      String resource = "mybatis-config.xml";      InputStream inputStream = Resources.getResourceAsStream(resource);      //2.创建SqlSessionFactoryBuilder对象      sqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();      //3.创建sqlSessionFactory对象      sqlSessionFactory factory=builder.build(inputStream);      //4.sqlSessionFactory生产SqlSession对象       SqlSession sqlsession=factory.openSession();      //5.sqlsession创建UserDao接口的代理对象      UserDao userdao = sqlsession.getMapper(UserDao.class);      //6.代理对象执行查询方法      List userList = userdao.getUserList();      for (User user : userList) {          System.out.println(user);        }      //7.释放资源      sqlsession.close();      inputStream.close();}

结果如下:

查询返回的resulttype是int resulttype返回类型_User_02

对这个例子做一下总结:它是基于XML配置文件的。从测试类开始看,读取mybatis-config.xml主配置文件,包含数据库连接的信息,在标签指定了sql映射文件的类路径:

<mappers>        <mapper resource="com/zhu/dao/UserMapper.xml"/>mappers>

读取配置文件就读到了UserMapper.xml配置文件,它和dao接口同目录,标签中namespace指定了dao接口的路径,下面的各种标签用来编写sql语句:增、删、改、查。

下面的查询标签中,id是该标签即sql语句的唯一标志,resultType指定了执行语句的返回结果类型。

namespace=    <select id="getUserList" resultType="com.zhu.pojo.User">    select * from user;  select>

读取完配置文件之后就是各种创建对象。

首先看看官网对于SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession三个对象的解释:

每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。

既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。

大致逻辑就是从主配置文件可以获取SqlSessionFactoryBuilder对象,它可以创建工厂对象SqlSessionFactory,SqlSessionFactory对象可以生产SqlSession对象,SqlSession对象可以用来执行编写的sql。

最后,采用动态代理的方法获取dao对象的代理对象,代理对象执行dao接口中操作数据库的方法。采用动态代理的方法获取dao对象的代理对象有以下注意点:

  1. dao接口要和mapper文件放在同一目录下
  2. dao接口和mapper文件名称尽量一致
  3. mapper文件中的namespace的值是dao的全限定名称
  4. mapper文件中的增、删、改、查的id是dao接口中的方法名。
//5.sqlsession创建UserDao接口的代理对象UserDao mapper = sqlsession.getMapper(UserDao.class);//6.代理对象执行查询方法List<User> userList = mapper.getUserList();

上面的6步只是为了更加详细点写清楚每一步的逻辑,参照官网,以上代码可以简化如下:

String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlsession=factory.openSession();UserDao userdao = sqlsession.getMapper(UserDao.class);ListuserList = userdao.getUserList();for (User user : userList) {  System.out.println(user);}

主配置文件在实际开发中也需要优化:

在主配置文件同目录建jdbc.properties文件:

jdbc.driver=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8jdbc.username=rootjdbc.password=root

主配置文件中引入jdbc.properties:

<configuration>    <properties resource="jdbc.properties">properties>    <settings>        <setting name="logImpl" value="STDOUT_LOGGING"/>    settings>        <typeAliases>                <typeAlias type="com.zhu.pojo.User" alias="user">typeAlias>                <package name="com.zhu">package>    typeAliases>    <environments default="development">        <environment id="development">            <transactionManager type="JDBC"/>            <dataSource type="POOLED">                <property name="driver" value="${jdbc.driver}"/>                <property name="url" value="${jdbc.url}"/>                <property name="username" value="${jdbc.username}"/>                <property name="password" value="${jdbc.password}"/>            dataSource>        environment>    environments>    <mappers>        <mapper resource="com/zhu/dao/UserMapper.xml"/>    mappers>configuration>

大致厘清Mybatis的执行思路之后,可以对代码进行封装来简化代码,编写MybatisUtils类:

public class MybatisUtils {    private static SqlSessionFactory sqlSessionFactory;    static{        try {            String resource = "mybatis-config.xml";            InputStream inputStream = Resources.getResourceAsStream(resource);            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);        } catch (IOException e) {            e.printStackTrace();        }    }    public static SqlSession getsqlsession(){        return sqlSessionFactory.openSession();    }}

测试代码如下:

@Testpublic void test1(){    SqlSession sqlsession = MybatisUtils.getsqlsession();    UserDao userdao = sqlsession.getMapper(UserDao.class);    List userList = userdao.getUserList();    for (User user : userList) {        System.out.println(user);    }}

上面介绍完来介绍一下其他的增删改查简单实现!

public interface UserDao {    //查询所有    ListgetUserList();    //按指定Id查找    User findById(Integer integer);    //增加一个用户    void insertUser(User user);    //按照指定id更改    int updateUser(User user);    //按照指定id删除    int deleteUser(Integer id);}
<?xml version="1.0" encoding="UTF-8" ?>/span>        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"        "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.zhu.dao.UserDao">        <select id="getUserList" resultType="com.zhu.pojo.User">    select * from user;    select>            <select id="findById" parameterType="Integer" resultType="com.zhu.pojo.User">        select * from user where id =#{uid}    select>            <insert id="insertUser">        insert into user (id,name,pwd)values(#{id},#{name},#{pwd})    insert>        <update id="updateUser" >        update user set name=#{name},pwd=#{pwd} where id=#{id}    update>        <delete id="deleteUser" >        delete from user where id=#{id}    delete>mapper>
public class UserDaoTest {    @Test    public void test1(){        SqlSession sqlsession = MybatisUtils.getsqlsession();        UserDao mapper = sqlsession.getMapper(UserDao.class);        List userList = mapper.getUserList();        for (User user : userList) {            System.out.println(user);        }    }    @Test    public void test2(){        SqlSession sqlsession = MybatisUtils.getsqlsession();        UserDao userdao = sqlsession.getMapper(UserDao.class);        User user = userdao.findById(2);        System.out.println(user);    }    @Test    public void test3(){        SqlSession sqlsession = MybatisUtils.getsqlsession();        UserDao userdao = sqlsession.getMapper(UserDao.class);        User user=new User();        user.setId(4);        user.setName("赵八");        user.setPwd("222544");        userdao.insertUser(user);        sqlsession.commit();    }    @Test    public void test4() throws IOException {        SqlSession sqlsession = MybatisUtils.getsqlsession();        UserDao userdao = sqlsession.getMapper(UserDao.class);        User user = userdao.findById(4);        user.setName("赵六六");        user.setPwd("22255444");        int res = userdao.updateUser(user);        System.out.println(res);        sqlsession.commit();    }    //删除指定编号    @Test    public void test5() throws Exception {        SqlSession sqlsession = MybatisUtils.getsqlsession();        UserDao userdao = sqlsession.getMapper(UserDao.class);        int res = userdao.deleteUser(4);        sqlsession.commit();        System.out.println(res);    }}

在上面的例子中,dao接口中的方法都是传递了一个参数,如果传递多个参数,传递参数有以下注意点:

  1. 传递一个简单的参数:#{任意字符}
  2. 传递多个简单类型的参数,使用@Param("自定义名称")
  3. 传递一个java对象,#{java对象的属性值},java对象要有构造方法和get方法
  4. 使用参数的位置,#{0},#{1},#{arg0},#{arg1}
  5. map作为参数,#{map的key}

最常用的是情况1和2,举个例子说明2:

//按照指定条件查询,查询id为 3或者姓名为张三的用户    List findByParam(@Param("myid") Integer id,@Param("myname") String name);
<select id="findByParam" resultType="com.zhu.pojo.User">        select * from user where id=#{myid} or name=#{myname}    select>
@Test    public void test21(){        SqlSession sqlsession = MybatisUtils.getsqlsession();        UserDao userdao = sqlsession.getMapper(UserDao.class);        List users = userdao.findByParam(3, "张三");        for (User user : users) {            System.out.println(user);        }    }

查询返回的resulttype是int resulttype返回类型_查询返回的resulttype是int_03

#和$的区别:

#是占位符,表示列值,放在等号右侧,指定PreparedStatement对象执行sql,效率高,没有sql注入风险。

$占位符,表示字符串的连接,把sql语句连接成字符串。

这两者都可以用在模糊查询中:

第一种方式,#{}中#{}实现向preparedStatement占位符设置值,自动进行java类型和jdbc类型转换,可以有效防止sql注入。

public interface UserDao {    ListfindByName(String name);}
<select id="findByName" parameterType="String" resultType="com.zhu.pojo.User">        select * from user where name like #{username}select>
@Test    public void testfindbyname() throws Exception {        SqlSession sqlsession = MybatisUtils.getsqlsession();        UserDao userdao = sqlsession.getMapper(UserDao.class);        List users = userdao.findByName("%王%");        for (User user : users) {            System.out.println(user);        }    }

查询返回的resulttype是int resulttype返回类型_查询返回的resulttype是int_04

第二种方式,${value}是固定的,基于statement,不进行java和jdbc的类型转换。

<select id="findByName" resultType="com.zhu.pojo.User">        select * from user where name like '%${value}%'    select>
@Test    public void testfindbyname() throws Exception {        SqlSession sqlsession = MybatisUtils.getsqlsession();        UserDao userdao = sqlsession.getMapper(UserDao.class);        List users = userdao.findByName("王");        for (User user : users) {            System.out.println(user);        }    }

查询返回的resulttype是int resulttype返回类型_mybatis resulttype类型_05

可以看出两种方法虽然结果相同,但实际执行的sql语句是不同的。

接着介绍一下Mybatis中参数设置。

parameterType:将会传入这条语句的参数的类全限定名或别名。传递的参数可以是基本类型,也可以是引用类型,还可以是实体类型(如User),还可以是实体类的包装类。如果注册了别名,可以直接用别名,常用的数据类型已经注册了别名。

这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset),开发中一般不写。

typeAliases:在SqlMapConfig.xml中配置

<typeAliases>     <typeAlias type="com.zhu.pojo.User" alias="user">typeAlias>       <package name="com.zhu">package>typeAliases>

扫描整个包下的类,指定别名后就不用了再写com.zhu.pojo.User了,别名就是类名,直接写user,首字母不区分大小写了。

查询返回的resulttype是int resulttype返回类型_bc_06

resultType:期望从这条语句中返回结果的类全限定名或别名。 注意,可以是任意的类型,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。支持基本类型和实体类型。如果注册了别名,可以直接用别名。但是不建议使用别名,如果多个包有相同的类会出现错误。

resultMap对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性,如果对其理解透彻,许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个。建立查询的列名和实体类名不一致时建立对应关系。举个例子:

新建实体类Myuser

public class Myuser {    private int userId;    private String userName;    private String userPwd;    构造方法、get/set、toString方法省略   }
ListgetMyserList();
<resultMap id="myusermap" type="myuser">        <id column="id" property="userId">id>        <result column="name" property="userName">result>        <result column="pwd" property="userPwd">result>resultMap><select id="getMyserList" resultMap="myusermap">         select * from user;select>

查询返回的resulttype是int resulttype返回类型_mybatis resulttype类型_07

<resultMap id="usermap" type="com.zhu.pojo.User">        column:列值,property:java对象的属性值        //主键用id        <id column="id" property="userId">id>        //非主键用result        <result column="name" property="userName">result>        <result column="pwd" property="userPwd">result>resultMap>    <select id="findAll" resultMap="usermap">        select * from user    select>

对于该例子,如果想达到同样结果,还可以这么做:

<select id="getMyserList" resultType="myuser">         select id as userId,name as userName,pwd as userPwd from user;select>

接着介绍动态sql。常用的标签有、、、、。

ListselectIf(User user);
<select id="selectIf" resultType="user">        select * from user where 1=1        <if test="name!=null and name!=''">            and name=#{name}        if>        <if test="id>0">            or id>#{id}        if>select>
@Test    public void test7(){        SqlSession sqlsession = MybatisUtils.getsqlsession();        UserDao userdao = sqlsession.getMapper(UserDao.class);        User user=new User();        user.setId(2);        user.setName("朱5");        List users = userdao.selectIf(user);        for (User u : users) {            System.out.println(u);        }    }

查询返回的resulttype是int resulttype返回类型_mybatis resulttype类型_08

<select id="selectWhere" resultType="user">        select *from user        <where>            <if test="name!=null and name!=''">                and name=#{name}            if>            <if test="id>0">                or id>#{id}            if>        where>select>

查询返回的resulttype是int resulttype返回类型_查询返回的resulttype是int_09

List selectForeach(Listlist);
<select id="selectForeach" resultType="user">        select *from user where id in        <foreach collection="list" open="(" close=")" item="id" separator=",">            #{id}        foreach>    select>
@Test    public void test9(){        SqlSession sqlsession = MybatisUtils.getsqlsession();        UserDao userdao = sqlsession.getMapper(UserDao.class);        Listlist=new ArrayList();        list.add(3);        list.add(7);        list.add(8);        List users = userdao.selectForeach(list);        for (User u : users) {            System.out.println(u);        }    }

查询返回的resulttype是int resulttype返回类型_User_10

这里集合中放的基本数据类型,如果放的是引用数据类型,标签里应改成如下

<foreach collection="list" open="(" close=")" item="id" separator=",">            #{Student.id}</foreach>

sql片段:用来复用重复代码片段。

"mysql">        select * from user
"selectWhere" resultType=        "mysql">        <where>            <if test="name!=null and name!=''">                and name=#{name}            if>            <if test="id>0">                or id>#{id}            if>        where>
<select id="selectForeach" resultType="user">        "mysql"/>         <foreach collection="list" open="(" close=")" item="id" separator=",">            #{id}        foreach>    select>

在Mybatis中,还有个小知识点:分页,用到的是PageHelper插件。

导入依赖和插件:

<dependency>            <groupId>com.github.pagehelpergroupId>            <artifactId>pagehelperartifactId>            <version>5.2.0version>dependency>
<plugins>        <plugin interceptor="com.github.pagehelper.PageInterceptor"/>plugins>
<select id="getUserList" resultType="user">    select * from user order by idselect>
@Test    public void test1(){        SqlSession sqlsession = MybatisUtils.getsqlsession();        UserDao mapper = sqlsession.getMapper(UserDao.class);        PageHelper.startPage(1,3);        List userList = mapper.getUserList();        for (User user : userList) {            System.out.println(user);        }    }

查询返回的resulttype是int resulttype返回类型_bc_11

至此,关于Mybatis框架的基于XML的基本使用介绍完毕。在第二篇中会介绍Mybatis如何多表查询、Mybatis延迟加载策略、Mybatis缓存以及基于注解开发使用Mybatis。