蒋振飞的博客 - Java进阶06:Mybatis教程   
正在加载蒋振飞的博客...
V3.0
蒋振飞的博客

Java进阶06:Mybatis教程

发布时间: 2019年01月30日 发布人: 蒋振飞 热度: 243 ℃ 评论数: 0

一、Mybatis概述

1.Mybatis介绍

    ①MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
    ②MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
    ③Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。

2.jdbc编程步骤

    ①加载数据库驱动
    ②创建并获取数据库链接
    ③创建jdbc statement对象
    ④设置sql语句
    ⑤设置sql语句中的参数(使用preparedStatement)
    ⑥通过statement执行sql并获取结果
    ⑦对sql执行结果进行解析处理
    ⑧释放资源(resultSet、preparedstatement、connection)

**jdbc程序**
public static void main(String[] args) {
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;
 
    try {
        // 加载数据库驱动
        Class.forName("com.mysql.jdbc.Driver");
 
        // 通过驱动管理类获取数据库链接
        connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "root");
        // 定义sql语句 ?表示占位符
        String sql = "select * from user where username = ?";
        // 获取预处理statement
        preparedStatement = connection.prepareStatement(sql);
        // 设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
        preparedStatement.setString(1, "王五");
        // 向数据库发出sql执行查询,查询出结果集
        resultSet = preparedStatement.executeQuery();
        // 遍历查询结果集
        while (resultSet.next()) {
            System.out.println(resultSet.getString("id") + "  " + resultSet.getString("username"));
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        // 释放资源
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        if (preparedStatement != null) {
            try {
                preparedStatement.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

3.jdbc问题总结

    ①数据库连接创建、释放频繁造成系统资源浪费,从而影响系统性能。如果使用数据库连接池可解决此问题。
    ②Sql语句在代码中硬编码,造成代码不易维护,实际应用中sql变化的可能较大,sql变动需要改变java代码。
    ③使用preparedStatement向占有位符号传参数存在硬编码,因为sql语句的where条件不一定,可能多也可能少,修改sql还要修改代码,系统不易维护。
    ④对结果集解析存在硬编码(查询列名),sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便。

4.Mybatis解决jdbc编程的问题

    ①数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库连接池可解决此问题。
        解决:在SqlMapConfig.xml中配置数据连接池,使用连接池管理数据库链接。
    ②Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
        解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。
    ③向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。
        解决:Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。
    ④对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。
        解决:Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。

5.mybatis与hibernate不同

    ①Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。
    ②Mybatis学习门槛低,简单易学,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。
    ③Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用hibernate开发可以节省很多代码,提高效率。但是Hibernate的学习门槛高,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡,以及怎样用好Hibernate需要具有很强的经验和能力才行。

    总之,按照用户的需求在有限的资源环境下只要能做出维护性、扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。

6.Mybatis架构

    ①mybatis配置
        SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
        mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
    ②通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂。
    ③由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
    ④mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
    ⑤Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
    ⑥Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
    ⑦Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。

7.SqlSession的使用范围

    SqlSession中封装了对数据库的操作,如:查询、插入、更新、删除等。 SqlSession通过SqlSessionFactory创建。 SqlSessionFactory是通过SqlSessionFactoryBuilder进行创建。

    1) SqlSessionFactoryBuilder

        SqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory创建的。所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。

    2) SqlSessionFactory

        SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory。

    3) SqlSession

        SqlSession是一个面向用户的接口,sqlSession中定义了数据库操作方法。每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。 打开一个 SqlSession;使用完毕就要关闭它。通常把这个关闭操作放到 finally 块中以确保每次都能执行关闭。如下:

SqlSession session = sqlSessionFactory.openSession();
try {
     // do work
} finally {
    session.close();
}

8.mybatis下载

    mybaits的代码由github.com管理,下载地址:https://github.com/mybatis/mybatis-3/releases

mybatis-3.2.7.jar     mybatis的核心包
lib文件夹              mybatis的依赖包所在
mybatis-3.2.7.pdf     mybatis使用手册

二、Mybatis入门程序

1.创建java工程

2.加入jar包

    Mybatis核心包、依赖包、数据驱动包。

3.加入配置文件

    创建资源文件夹config,加入log4j.properties和SqlMapConfig.xml配置文件。

    1) log4j.properties

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

    2) SqlMapConfig.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>
    <!-- 和spring整合后 environments配置将废除 -->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事务管理 -->
            <transactionManager type="JDBC" />
            <!-- 数据库连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url"
                    value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
                <property name="username" value="root" />
                <property name="password" value="root" />
            </dataSource>
        </environment>
    </environments>
 
    <!-- 加载映射文件 -->
    <mappers>
        <mapper resource="sqlmap/User.xml" />
    </mappers>
</configuration>

4.创建pojo类

    pojo类作为mybatis进行sql映射使用,po类通常与数据库表对应。

Public class User {
    private int id;
    private String username;// 用户姓名
    private String sex;// 性别
    private Date birthday;// 生日
    private String address;// 地址
 
get/set……

5.sql映射文件

    在config下的sqlmap目录下创建sql映射文件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">
<!-- namespace:命名空间,用于隔离sql -->
<mapper namespace="test">
</mapper>

6.加载映射文件

    mybatis框架需要加载Mapper.xml映射文件,将users.xml添加在SqlMapConfig.xml。

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

7.映射文件

    在user.xml中添加select标签,编写sql。

<?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:命名空间,用于隔离sql,还有一个很重要的作用,后面会讲 -->
<mapper namespace="test">
 
    <!-- id:statement的id 或者叫做sql的id-->
    <!-- parameterType:声明输入参数的类型 -->
    <!-- resultType:声明输出结果的类型,应该填写pojo的全路径 -->
    <!-- #{}:输入参数的占位符,相当于jdbc的? -->
    <select id="queryUserById" parameterType="int"
        resultType="com.jzfblog.mybatis.pojo.User">
        SELECT * FROM `user` WHERE id  = #{id}
    </select>
 
</mapper>

8.测试程序

    ①创建SqlSessionFactoryBuilder对象
    ②加载SqlMapConfig.xml配置文件
    ③创建SqlSessionFactory对象
    ④创建SqlSession对象
    ⑤执行SqlSession对象执行查询,获取结果User
    ⑥打印结果
    ⑦释放资源

public class MybatisTest {
    private SqlSessionFactory sqlSessionFactory = null;
 
    @Before
    public void init() throws Exception {
        // 1. 创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
 
        // 2. 加载SqlMapConfig.xml配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
 
        // 3. 创建SqlSessionFactory对象
        this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
    }
 
    @Test
    public void testQueryUserById() throws Exception {
        // 4. 创建SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
 
        // 5. 执行SqlSession对象执行查询,获取结果User
        // 第一个参数是User.xml的statement的id,第二个参数是执行sql需要的参数;
        Object user = sqlSession.selectOne("queryUserById", 1);
 
        // 6. 打印结果
        System.out.println(user);
 
        // 7. 释放资源
        sqlSession.close();
    }
}

9.实现根据用户名模糊查询用户

    1) 方法一

        ①映射文件

            在User.xml配置文件中添加如下内容:

<!-- 如果返回多个结果,mybatis会自动把返回的结果放在list容器中 -->
<!-- resultType的配置和返回一个结果的配置一样 -->
<select id="queryUserByUsername1" parameterType="string"
    resultType="cn.jzfblog.mybatis.pojo.User">
    SELECT * FROM `user` WHERE username LIKE #{username}
</select>

        ②测试程序

@Test
public void testQueryUserByUsername1() throws Exception {
    // 4. 创建SqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
 
    // 5. 执行SqlSession对象执行查询,获取结果User
    // 查询多条数据使用selectList方法
    List<Object> list = sqlSession.selectList("queryUserByUsername1", "%王%");
 
    // 6. 打印结果
    for (Object user : list) {
        System.out.println(user);
    }
 
    // 7. 释放资源
    sqlSession.close();
}

    2) 方法二

        ①映射文件

            在User.xml配置文件中添加如下内容:

<!-- 如果传入的参数是简单数据类型,${}里面必须写value -->
<select id="queryUserByUsername2" parameterType="string"
    resultType="cn.jzfblog.mybatis.pojo.User">
    SELECT * FROM `user` WHERE username LIKE '%${value}%'
</select>

        ②测试程序

@Test
public void testQueryUserByUsername2() throws Exception {
    // 4. 创建SqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
 
    // 5. 执行SqlSession对象执行查询,获取结果User
    // 查询多条数据使用selectList方法
    List<Object> list = sqlSession.selectList("queryUserByUsername2", "王");
 
    // 6. 打印结果
    for (Object user : list) {
        System.out.println(user);
    }
 
    // 7. 释放资源
    sqlSession.close();
}

10.小结

    1) #{}和${}

        ①#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换。
        ②#{}可以有效防止sql注入。
        ③#{}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
        ④${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换。
        ⑤${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。

    2) parameterType和resultType

        ①parameterType:指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接在sql中。
        ②resultType:指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。如果有多条数据,则分别进行映射,并把对象放到容器List中

    3) selectOne和selectList

        ①selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常:

org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:70)

        ②selectList可以查询一条或多条记录。

三、Mybatis其他基本操作

1.实现添加用户

    1) 映射文件

        在User.xml配置文件中添加如下内容:

<!-- 保存用户 -->
<insert id="saveUser" parameterType="cn.jzfblog.mybatis.pojo.User">
    INSERT INTO `user`
    (username,birthday,sex,address) VALUES
    (#{username},#{birthday},#{sex},#{address})
</insert>

    2) 测试程序

@Test
public void testSaveUser() {
    // 4. 创建SqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
 
    // 5. 执行SqlSession对象执行保存
    // 创建需要保存的User
    User user = new User();
    user.setUsername("张飞");
    user.setSex("1");
    user.setBirthday(new Date());
    user.setAddress("蜀国");
 
    sqlSession.insert("saveUser", user);
    System.out.println(user);
 
    // 需要进行事务提交
    sqlSession.commit();
 
    // 7. 释放资源
    sqlSession.close();
}

2.mysql自增主键返回

    1) 查询id的sql

        LASTINSERTID():是mysql的函数,返回auto_increment自增列新记录id值。

    2) mysql自增主键返回

        通过修改User.xml映射文件,可以将mysql自增主键返回,如下添加selectKey 标签:

<!-- 保存用户 -->
<insert id="saveUser" parameterType="cn.jzfblog.mybatis.pojo.User">
    <!-- selectKey 标签实现主键返回 -->
    <!-- keyColumn:主键对应的表中的哪一列 -->
    <!-- keyProperty:主键对应的pojo中的哪一个属性 -->
    <!-- order:设置在执行insert语句前执行查询id的sql,孩纸在执行insert语句之后执行查询id的sql -->
    <!-- resultType:设置返回的id的类型 -->
    <selectKey keyColumn="id" keyProperty="id" order="AFTER"
        resultType="int">
        SELECT LAST_INSERT_ID()
    </selectKey>
    INSERT INTO `user`
    (username,birthday,sex,address) VALUES
    (#{username},#{birthday},#{sex},#{address})
</insert>

3.Mysql使用 uuid实现主键

    需要增加通过select uuid()得到uuid值,注意这里使用的order是“BEFORE”。

<!-- 保存用户 -->
<insert id="saveUser" parameterType="cn.jzfblog.mybatis.pojo.User">
    <!-- selectKey 标签实现主键返回 -->
    <!-- keyColumn:主键对应的表中的哪一列 -->
    <!-- keyProperty:主键对应的pojo中的哪一个属性 -->
    <!-- order:设置在执行insert语句前执行查询id的sql,孩纸在执行insert语句之后执行查询id的sql -->
    <!-- resultType:设置返回的id的类型 -->
    <selectKey keyColumn="id" keyProperty="id" order="BEFORE"
        resultType="string">
        SELECT LAST_INSERT_ID()
    </selectKey>
    INSERT INTO `user`
    (username,birthday,sex,address) VALUES
    (#{username},#{birthday},#{sex},#{address})
</insert>

4.实现修改用户

    1) 映射文件

        在User.xml配置文件中添加如下内容:

<!-- 更新用户 -->
<update id="updateUserById" parameterType="cn.jzfblog.mybatis.pojo.User">
    UPDATE `user` SET
    username = #{username} WHERE id = #{id}
</update>

    2) 测试程序

@Test
public void testUpdateUserById() {
    // 4. 创建SqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
 
    // 5. 执行SqlSession对象执行更新
    // 创建需要更新的User
    User user = new User();
    user.setId(26);
    user.setUsername("关羽");
    user.setSex("1");
    user.setBirthday(new Date());
    user.setAddress("蜀国");
 
    sqlSession.update("updateUserById", user);
 
    // 需要进行事务提交
    sqlSession.commit();
 
    // 7. 释放资源
    sqlSession.close();
}

5.实现删除用户

    1) 映射文件

        在User.xml配置文件中添加如下内容:

<!-- 删除用户 -->
<delete id="deleteUserById" parameterType="int">
    delete from user where
    id=#{id}
</delete>

    2) 测试程序

@Test
public void testDeleteUserById() {
    // 4. 创建SqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
 
    // 5. 执行SqlSession对象执行删除
    sqlSession.delete("deleteUserById", 48);
 
    // 6.需要进行事务提交
    sqlSession.commit();
 
    // 7. 释放资源
    sqlSession.close();
}

四、原始Dao开发

1.映射文件

<?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:命名空间,用于隔离sql,还有一个很重要的作用,后面会讲 -->
<mapper namespace="test">
 
    <!-- 根据id查询用户 -->
    <select id="queryUserById" parameterType="int"
        resultType="cn.jzfblog.mybatis.pojo.User">
        select * from user where id = #{id}
    </select>
 
    <!-- 根据username模糊查询用户 -->
    <select id="queryUserByUsername" parameterType="string"
        resultType="cn.jzfblog.mybatis.pojo.User">
        select * from user where username like '%${value}%'
    </select>
 
    <!-- 保存用户 -->
    <insert id="saveUser" parameterType="cn.jzfblog.mybatis.pojo.User">
        <selectKey keyProperty="id" keyColumn="id" order="AFTER"
            resultType="int">
            SELECT LAST_INSERT_ID()
        </selectKey>
        insert into user(username,birthday,sex,address)
        values(#{username},#{birthday},#{sex},#{address})
    </insert>
 
</mapper>

2.Dao接口

    先进行DAO的接口开发,编码如下:

public interface UserDao {
    /**
     * 根据id查询用户
     * 
     * @param id
     * @return
     */
    User queryUserById(int id);
 
    /**
     * 根据用户名模糊查询用户
     * 
     * @param username
     * @return
     */
    List<User> queryUserByUsername(String username);
 
    /**
     * 保存用户
     * 
     * @param user
     */
    void saveUser(User user);
}

3.Dao实现类

public class UserDaoImpl implements UserDao {
    private SqlSessionFactory sqlSessionFactory;
 
    public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
        super();
        this.sqlSessionFactory = sqlSessionFactory;
    }
 
    @Override
    public User queryUserById(int id) {
        // 创建SqlSession
        SqlSession sqlSession = this.sqlSessionFactory.openSession();
        // 执行查询逻辑
        User user = sqlSession.selectOne("queryUserById", id);
        // 释放资源
        sqlSession.close();
 
        return user;
    }
 
    @Override
    public List<User> queryUserByUsername(String username) {
        // 创建SqlSession
        SqlSession sqlSession = this.sqlSessionFactory.openSession();
 
        // 执行查询逻辑
        List<User> list = sqlSession.selectList("queryUserByUsername", username);
        // 释放资源
        sqlSession.close();
        return list;
    }
 
    @Override
    public void saveUser(User user) {
        // 创建SqlSession
        SqlSession sqlSession = this.sqlSessionFactory.openSession();
 
        // 执行保存逻辑
        sqlSession.insert("saveUser", user);
        // 提交事务
        sqlSession.commit();
        // 释放资源
        sqlSession.close();
    }
}

4.Dao测试

    创建一个JUnit的测试类,对UserDao进行测试,测试代码如下:

public class UserDaoTest {
    private SqlSessionFactory sqlSessionFactory;
 
    @Before
    public void init() throws Exception {
        // 创建SqlSessionFactoryBuilder
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        // 加载SqlMapConfig.xml配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 创建SqlsessionFactory
        this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
    }
 
    @Test
    public void testQueryUserById() {
        // 创建DAO
        UserDao userDao = new UserDaoImpl(this.sqlSessionFactory);
        // 执行查询
        User user = userDao.queryUserById(1);
        System.out.println(user);
    }
 
    @Test
    public void testQueryUserByUsername() {
        // 创建DAO
 
        UserDao userDao = new UserDaoImpl(this.sqlSessionFactory);
        // 执行查询
        List<User> list = userDao.queryUserByUsername("张");
        for (User user : list) {
            System.out.println(user);
        }
    }
    @Test
    public void testSaveUser() {
        // 创建DAO
        UserDao userDao = new UserDaoImpl(this.sqlSessionFactory);

        // 创建保存对象
        User user = new User();
        user.setUsername("刘备");
        user.setBirthday(new Date());
        user.setSex("1");
        user.setAddress("蜀国");
        // 执行保存
        userDao.saveUser(user);

        System.out.println(user);
    }
}

5.原始Dao开发中存在以下问题

    ①Dao方法体存在重复代码:通过SqlSessionFactory创建SqlSession,调用SqlSession的数据库操作方法。
    ②调用sqlSession的数据库操作方法需要指定statement的id,这里存在硬编码,不得于开发维护。

五、Mapper动态代理方式

1.开发规范

    Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。

    Mapper接口开发需要遵循以下规范:

        ①Mapper.xml文件中的namespace与mapper接口的类路径相同。
        ②Mapper接口方法名和Mapper.xml中定义的每个statement的id相同。 
        ③Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同。
        ④Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同。

2.Mapper.xml(映射文件)

    定义mapper映射文件UserMapper.xml,将UserMapper.xml放在config下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">
<!-- namespace:命名空间,用于隔离sql -->
<!-- 还有一个很重要的作用,使用动态代理开发DAO,1. namespace必须和Mapper接口类路径一致 -->
<mapper namespace="cn.jzfblog.mybatis.mapper.UserMapper">
    <!-- 根据用户id查询用户 -->
    <!-- 2. id必须和Mapper接口方法名一致 -->
    <!-- 3. parameterType必须和接口方法参数类型一致 -->
    <!-- 4. resultType必须和接口方法返回值类型一致 -->
    <select id="queryUserById" parameterType="int"
        resultType="cn.jzfblog.mybatis.pojo.User">
        select * from user where id = #{id}
    </select>
 
    <!-- 根据用户名查询用户 -->
    <select id="queryUserByUsername" parameterType="string"
        resultType="cn.jzfblog.mybatis.pojo.User">
        select * from user where username like '%${value}%'
    </select>
 
    <!-- 保存用户 -->
    <insert id="saveUser" parameterType="cn.jzfblog.mybatis.pojo.User">
        <selectKey keyProperty="id" keyColumn="id" order="AFTER"
            resultType="int">
            select last_insert_id()
        </selectKey>
        insert into user(username,birthday,sex,address) values
        (#{username},#{birthday},#{sex},#{address});
    </insert>
</mapper>

3.UserMapper(接口文件)

public interface UserMapper {
    /**
     * 根据id查询
     * 
     * @param id
     * @return
     */
    User queryUserById(int id);
 
    /**
     * 根据用户名查询用户
     * 
     * @param username
     * @return
     */
    List<User> queryUserByUsername(String username);
 
    /**
     * 保存用户
     * 
     * @param user
     */
    void saveUser(User user);
}

4.加载UserMapper.xml文件

    修改SqlMapConfig.xml文件,添加以下所示的内容。

<!-- 加载映射文件 -->
<mappers>
    <mapper resource="sqlmap/User.xml" />
    <mapper resource="mapper/UserMapper.xml" />
</mappers>

5.测试方法

public class UserMapperTest {
    private SqlSessionFactory sqlSessionFactory;
 
    @Before
    public void init() throws Exception {
        // 创建SqlSessionFactoryBuilder
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        // 加载SqlMapConfig.xml配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 创建SqlsessionFactory
        this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
    }
 
    @Test
    public void testQueryUserById() {
        // 获取sqlSession,和spring整合后由spring管理
        SqlSession sqlSession = this.sqlSessionFactory.openSession();
 
        // 从sqlSession中获取Mapper接口的代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 执行查询方法
        User user = userMapper.queryUserById(1);
        System.out.println(user);
 
        // 和spring整合后由spring管理
        sqlSession.close();
    }
 
    @Test
    public void testQueryUserByUsername() {
        // 获取sqlSession,和spring整合后由spring管理
        SqlSession sqlSession = this.sqlSessionFactory.openSession();
 
        // 从sqlSession中获取Mapper接口的代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 执行查询方法 
        List<User> list = userMapper.queryUserByUsername("张");
        for (User user : list) {
            System.out.println(user);
        }
 
        // 和spring整合后由spring管理
        sqlSession.close();
    }
 
    @Test
    public void testSaveUser() {
        // 获取sqlSession,和spring整合后由spring管理
        SqlSession sqlSession = this.sqlSessionFactory.openSession();
 
        // 从sqlSession中获取Mapper接口的代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 创建保存对象
        User user = new User();
        user.setUsername("刘备");
        user.setBirthday(new Date());
        user.setSex("1");
        user.setAddress("蜀国");
        // 执行查询方法
        userMapper.saveUser(user);
        System.out.println(user);
 
        // 和spring整合后由spring管理
        sqlSession.commit();
        sqlSession.close();
    }
}

6.小结

    1) selectOne和selectList

        动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。

    2) namespace

        mybatis官方推荐使用mapper代理方法开发mapper接口,程序员不用编写mapper接口实现类,使用mapper代理方法时,输入参数可以使用pojo包装对象或map对象,保证dao的通用性。

六、SqlMapConfig.xml配置文件

1.配置内容

    SqlMapConfig.xml中配置的内容和顺序如下

properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
    environment(环境子属性对象)
        transactionManager(事务管理)
        dataSource(数据源)
mappers(映射器)

2.properties(属性)

    SqlMapConfig.xml可以引用java属性文件中的配置信息,在config下定义db.properties文件。

    1) db.properties配置文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root

    2) SqlMapConfig.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>
    <!-- 是用resource属性加载外部配置文件 -->
    <properties resource="db.properties">
        <!-- 在properties内部用property定义属性 -->
        <!-- 如果外部配置文件有该属性,则内部定义属性被外部属性覆盖 -->
        <property name="jdbc.username" value="root123" />
        <property name="jdbc.password" value="root123" />
    </properties>
 
    <!-- 和spring整合后 environments配置将废除 -->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事务管理 -->
            <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="sqlmap/User.xml" />
        <mapper resource="mapper/UserMapper.xml" />
    </mappers>
</configuration>

3.typeAliases(类型别名)

    1) mybatis支持别名

别名  映射的类型
_byte   byte 
_long   long 
_short  short 
_int    int 
_integer    int 
_double     double 
_float  float 
_boolean    boolean 
string  String 
byte    Byte 
long    Long 
short   Short 
int     Integer 
integer     Integer 
double  Double 
float   Float 
boolean     Boolean 
date    Date 
decimal     BigDecimal 
bigdecimal  BigDecimal 
map Map

    2) 自定义别名

        在SqlMapConfig.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>
    <!-- 是用resource属性加载外部配置文件 -->
    <properties resource="db.properties">
        <!-- 在properties内部用property定义属性 -->
        <property name="jdbc.username" value="root123" />
        <property name="jdbc.password" value="root123" />
    </properties>
 
    <typeAliases>
        <!-- 单个别名定义 -->
        <typeAlias alias="user" type="cn.jzfblog.mybatis.pojo.User" />
        <!-- 批量别名定义,扫描整个包下的类,别名为类名(大小写不敏感) -->
        <package name="cn.jzfblog.mybatis.pojo" />
        <package name="其它包" />
    </typeAliases>
 
    <!-- 和spring整合后 environments配置将废除 -->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事务管理 -->
            <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="sqlmap/User.xml" />
        <mapper resource="mapper/UserMapper.xml" />
    </mappers>
</configuration>

    在mapper.xml配置文件中,就可以使用设置的别名了,别名大小写不敏感。

4.mappers(映射器)

    Mapper配置的几种方法:

    1) 使用相对于类路径的资源

<mapper resource="sqlmap/User.xml" />

    2) 使用mapper接口类路径

<mapper class="cn.jzfblog.mybatis.mapper.UserMapper"/>

        注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

    3) 注册指定包下的所有mapper接口

<package name="cn.jzfblog.mybatis.mapper"/>

        注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

七、传递pojo包装对象

1.编写QueryVo

public class QueryVo {
    // 包含其他的pojo
    private User user;
 
    public User getUser() {
        return user;
    }
    public void setUser(User user) {
        this.user = user;
    }
}

2.Mapper.xml文件

<!-- 使用包装类型查询用户 -->
<select id="queryUserByQueryVo" parameterType="queryVo" resultType="user">
    SELECT * FROM 'user' WHERE username LIKE '%${user.username}%'
</select>

3.Mapper接口

List<User> queryUserByQueryVo(QueryVo queryVo);

4.测试方法

@Test
public void testQueryUserByQueryVo() {
    // mybatis和spring整合,整合之后,交给spring管理
    SqlSession sqlSession = this.sqlSessionFactory.openSession();
    // 创建Mapper接口的动态代理对象,整合之后,交给spring管理
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 
    // 使用userMapper执行查询,使用包装对象
    QueryVo queryVo = new QueryVo();
    // 设置user条件
    User user = new User();
    user.setUsername("张");
    // 设置到包装对象中
    queryVo.setUser(user);
 
    // 执行查询
    List<User> list = userMapper.queryUserByQueryVo(queryVo);
    for (User u : list) {
        System.out.println(u);
    }
 
    // mybatis和spring整合,整合之后,交给spring管理
    sqlSession.close();
}

八、动态sql

1.If标签

<!-- 根据条件查询用户 -->
<select id="queryUserByWhere" parameterType="user" resultType="user">
    SELECT id, username, birthday, sex, address FROM `user`
    WHERE sex = #{sex} AND username LIKE
    '%${username}%'
</select>

2.Mapper接口

List<User> queryUserByWhere(User user);

3.测试方法

@Test
public void testQueryUserByWhere() {
    // mybatis和spring整合,整合之后,交给spring管理
    SqlSession sqlSession = this.sqlSessionFactory.openSession();
    // 创建Mapper接口的动态代理对象,整合之后,交给spring管理
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 
    // 使用userMapper执行根据条件查询用户
    User user = new User();
    user.setSex("1");
    user.setUsername("张");
 
    List<User> list = userMapper.queryUserByWhere(user);
 
    for (User u : list) {
        System.out.println(u);
    }
 
    // mybatis和spring整合,整合之后,交给spring管理
    sqlSession.close();
}

4.使用if标签

    改造UserMapper.xml,如下:

<!-- 根据条件查询用户 -->
<select id="queryUserByWhere" parameterType="user" resultType="user">
    SELECT id, username, birthday, sex, address FROM `user`
    WHERE 1=1
    <if test="sex != null and sex != ''">
        AND sex = #{sex}
    </if>
    <if test="username != null and username != ''">
        AND username LIKE
        '%${username}%'
    </if>
</select>

    注意字符串类型的数据需要做不等于空字符串校验。

5.Where标签

    上面的sql还有where 1=1 这样的语句,很麻烦,可以使用where标签进行改造。

    改造UserMapper.xml,如下:

<!-- 根据条件查询用户 -->
<select id="queryUserByWhere" parameterType="user" resultType="user">
    SELECT id, username, birthday, sex, address FROM `user`
<!-- where标签可以自动添加where,同时处理sql语句中第一个and关键字 -->
    <where>
        <if test="sex != null">
            AND sex = #{sex}
        </if>
        <if test="username != null and username != ''">
            AND username LIKE
            '%${username}%'
        </if>
    </where>
</select>

6.Sql片段

    Sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的。

<!-- 根据条件查询用户 -->
<select id="queryUserByWhere" parameterType="user" resultType="user">
    <!-- SELECT id, username, birthday, sex, address FROM `user` -->
    <!-- 使用include标签加载sql片段;refid是sql片段id -->
    SELECT <include refid="userFields" /> FROM `user`
    <!-- where标签可以自动添加where关键字,同时处理sql语句中第一个and关键字 -->
    <where>
        <if test="sex != null">
            AND sex = #{sex}
        </if>
        <if test="username != null and username != ''">
            AND username LIKE
            '%${username}%'
        </if>
    </where>
</select>
 
<!-- 声明sql片段 -->
<sql id="userFields">
    id, username, birthday, sex, address
</sql>

    如果要使用别的Mapper.xml配置的sql片段,可以在refid前面加上对应的Mapper.xml的namespace。

7.foreach标签

    向sql传递数组或List,mybatis使用foreach解析,如下:

<!-- 根据ids查询用户 -->
<select id="queryUserByIds" parameterType="queryVo" resultType="user">
    SELECT * FROM `user`
    <where>
        <!-- foreach标签,进行遍历 -->
        <!-- collection:遍历的集合,这里是QueryVo的ids属性 -->
        <!-- item:遍历的项目,可以随便写,,但是和后面的#{}里面要一致 -->
        <!-- open:在前面添加的sql片段 -->
        <!-- close:在结尾处添加的sql片段 -->
        <!-- separator:指定遍历的元素之间使用的分隔符 -->
        <foreach collection="ids" item="item" open="id IN (" close=")"
            separator=",">
            #{item}
        </foreach>
    </where>
</select>

    测试方法

@Test
public void testQueryUserByIds() {
    // mybatis和spring整合,整合之后,交给spring管理
    SqlSession sqlSession = this.sqlSessionFactory.openSession();
    // 创建Mapper接口的动态代理对象,整合之后,交给spring管理
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 
    // 使用userMapper执行根据条件查询用户
    QueryVo queryVo = new QueryVo();
    List<Integer> ids = new ArrayList<>();
    ids.add(1);
    ids.add(10);
    ids.add(24);
    queryVo.setIds(ids);
 
    List<User> list = userMapper.queryUserByIds(queryVo);
 
    for (User u : list) {
        System.out.println(u);
    }
 
    // mybatis和spring整合,整合之后,交给spring管理
    sqlSession.close();
}

九、一对一查询

1.查询所有订单信息,关联查询下单用户信息

SELECT
    o.id,
    o.user_id userId,
    o.number,
    o.createtime,
    o.note,
    u.username,
    u.address
FROM
    `order` o
LEFT JOIN `user` u ON o.user_id = u.id

2.使用resultType(方法一)

    使用resultType,改造订单pojo类,此pojo类中包括了订单信息和用户信息,这样返回对象的时候,mybatis自动把用户信息也注入进来了。

    1) 改造pojo类

        OrderUser类继承Order类后OrderUser类包括了Order类的所有字段,只需要定义用户的信息字段即可。

public class OrderUser extends Order{
    private String username;
    private String address;
}

    2) Mapper.xml

        在UserMapper.xml添加sql,如下

<!-- 查询订单,同时包含用户数据 -->
<select id="queryOrderUser" resultType="orderUser">
    SELECT
    o.id,
    o.user_id
    userId,
    o.number,
    o.createtime,
    o.note,
    u.username,
    u.address
    FROM
    `order` o
    LEFT JOIN `user` u ON o.user_id = u.id
</select>

    3) Mapper接口

List<OrderUser> queryOrderUser();

    4) 测试方法

@Test
public void testQueryOrderUser() {
    // mybatis和spring整合,整合之后,交给spring管理
    SqlSession sqlSession = this.sqlSessionFactory.openSession();
    // 创建Mapper接口的动态代理对象,整合之后,交给spring管理
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 
    // 使用userMapper执行根据条件查询用户
    List<OrderUser> list = userMapper.queryOrderUser();
 
    for (OrderUser ou : list) {
        System.out.println(ou);
    }
 
    // mybatis和spring整合,整合之后,交给spring管理
    sqlSession.close();
}

3.使用resultMap(方法二)

    使用resultMap,定义专门的resultMap用于映射一对一查询结果。

    1) 改造pojo类

public class Order{
 
    // 订单id
    private int id;
    // 用户id
    private Integer userId;
    // 订单号
    private String number;
    // 订单创建时间
    private Date createtime;
    // 备注
    private String note;
 
    private User user;
}

    2) Mapper.xml

        这里resultMap指定orderUserResultMap,如下:

<resultMap type="order" id="orderUserResultMap">
    <id property="id" column="id" />
    <result property="userId" column="user_id" />
    <result property="number" column="number" />
    <result property="createtime" column="createtime" />
    <result property="note" column="note" />
 
    <!-- association :配置一对一属性 -->
    <!-- property:order里面的User属性名 -->
    <!-- javaType:属性类型 -->
    <association property="user" javaType="user">
        <!-- id:声明主键,表示user_id是关联查询对象的唯一标识-->
        <id property="id" column="user_id" />
        <result property="username" column="username" />
        <result property="address" column="address" />
    </association>
 
</resultMap>
 
<!-- 一对一关联,查询订单,订单内部包含用户属性 -->
<select id="queryOrderUserResultMap" resultMap="orderUserResultMap">
    SELECT
    o.id,
    o.user_id,
    o.number,
    o.createtime,
    o.note,
    u.username,
    u.address
    FROM
    `order` o
    LEFT JOIN `user` u ON o.user_id = u.id
</select>

十、一对多查询

1.查询所有用户信息及用户关联的订单信息

SELECT
    u.id,
    u.username,
    u.birthday,
    u.sex,
    u.address,
    o.id oid,
    o.number,
    o.createtime,
    o.note
FROM
    `user` u
LEFT JOIN `order` o ON u.id = o.user_id

2.修改pojo类

    在User类中加入List orders属性。

public class User {
 
    private int id;
    private String username;
    private String sex;
    private Date birthday;
    private String address;
 
    private List<Order> orders;
}

3.Mapper.xml

<resultMap type="user" id="userOrderResultMap">
    <id property="id" column="id" />
    <result property="username" column="username" />
    <result property="birthday" column="birthday" />
    <result property="sex" column="sex" />
    <result property="address" column="address" />
 
    <!-- 配置一对多的关系 -->
    <collection property="orders" javaType="list" ofType="order">
        <!-- 配置主键,是关联Order的唯一标识 -->
        <id property="id" column="oid" />
        <result property="number" column="number" />
        <result property="createtime" column="createtime" />
        <result property="note" column="note" />
    </collection>
</resultMap>
 
<!-- 一对多关联,查询订单同时查询该用户下的订单 -->
<select id="queryUserOrder" resultMap="userOrderResultMap">
    SELECT
    u.id,
    u.username,
    u.birthday,
    u.sex,
    u.address,
    o.id oid,
    o.number,
    o.createtime,
    o.note
    FROM
    `user` u
    LEFT JOIN `order` o ON u.id = o.user_id
</select>

4.Mapper接口

List<User> queryUserOrder();

5.测试方法

@Test
public void testQueryUserOrder() {
    // mybatis和spring整合,整合之后,交给spring管理
    SqlSession sqlSession = this.sqlSessionFactory.openSession();
    // 创建Mapper接口的动态代理对象,整合之后,交给spring管理
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 
    // 使用userMapper执行根据条件查询用户
    List<User> list = userMapper.queryUserOrder();
 
    for (User u : list) {
        System.out.println(u);
    }
 
    // mybatis和spring整合,整合之后,交给spring管理
    sqlSession.close();
}

十一、Mybatis整合spring

1.整合思路

    ①SqlSessionFactory对象应该放到spring容器中作为单例存在。
    ②传统dao的开发方式中,应该从spring容器中获得sqlsession对象。
    ③Mapper代理形式中,应该从spring容器中直接获得mapper的代理对象。
    ④数据库的连接以及数据库连接池事务管理都交给spring容器来完成。

2.整合需要的jar包

    ①spring的jar包。
    ②Mybatis的jar包。
    ③Spring+mybatis的整合包。
    ④Mysql的数据库驱动jar包。
    ⑤数据库连接池的jar包。

3.整合的步骤

    1) 创建工程

    2) 导入jar包

    3) 加入配置文件

        ①SqlMapConfig.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>
    <!-- 设置别名 -->
    <typeAliases>
        <!-- 2. 指定扫描包,会把包内所有的类都设置别名,别名的名称就是类名,大小写不敏感 -->
        <package name="com.jzfblog.mybatis.pojo" />
    </typeAliases>
 
</configuration>

        ②applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
 
   <!-- 加载配置文件 -->
   <context:property-placeholder location="classpath:db.properties" />
 
    <!-- 数据库连接池 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName" value="${jdbc.driver}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="maxActive" value="10" />
        <property name="maxIdle" value="5" />
    </bean>
 
    <!-- 配置SqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 配置mybatis核心配置文件 -->
        <property name="configLocation" value="classpath:SqlMapConfig.xml" />
        <!-- 配置数据源 -->
        <property name="dataSource" ref="dataSource" />
    </bean>
</beans>

        ③db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root

        ④log4j.properties

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

4.传统dao的开发方式

    1) 编写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="test">
    <!-- 根据用户id查询 -->
    <select id="queryUserById" parameterType="int" resultType="user">
        select * from user where id = #{id}
    </select>
 
    <!-- 根据用户名模糊查询用户 -->
    <select id="queryUserByUsername" parameterType="string"
        resultType="user">
        select * from user where username like '%${value}%'
    </select>
 
    <!-- 添加用户 -->
    <insert id="saveUser" parameterType="user">
        <selectKey keyProperty="id" keyColumn="id" order="AFTER"
            resultType="int">
            select last_insert_id()
        </selectKey>
        insert into user
        (username,birthday,sex,address)
        values
        (#{username},#{birthday},#{sex},#{address})
    </insert>
 
</mapper>

    2) 加载Mapper.xml

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

    3) 实现UserDao接口

public interface UserDao {
    /**
     * 根据id查询用户
     * 
     * @param id
     * @return
     */
    User queryUserById(int id);
 
    /**
     * 根据用户名模糊查询用户列表
     * 
     * @param username
     * @return
     */
    List<User> queryUserByUsername(String username);
 
    /**
     * 保存
     * 
     * @param user
     */
    void saveUser(User user);
 
}

    4) 实现UserDaoImpl实现类

    编写DAO实现类,实现类必须集成SqlSessionDaoSupport,SqlSessionDaoSupport提供getSqlSession()方法来获取SqlSession。

public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
    @Override
    public User queryUserById(int id) {
        // 获取SqlSession
        SqlSession sqlSession = super.getSqlSession();
 
        // 使用SqlSession执行操作
        User user = sqlSession.selectOne("queryUserById", id);
 
        // 不要关闭sqlSession
 
        return user;
    }
 
    @Override
    public List<User> queryUserByUsername(String username) {
        // 获取SqlSession
        SqlSession sqlSession = super.getSqlSession();
 
        // 使用SqlSession执行操作
        List<User> list = sqlSession.selectList("queryUserByUsername", username);
 
        // 不要关闭sqlSession
 
        return list;
    }
 
    @Override
    public void saveUser(User user) {
        // 获取SqlSession
        SqlSession sqlSession = super.getSqlSession();
 
        // 使用SqlSession执行操作
        sqlSession.insert("saveUser", user);
 
        // 不用提交,事务由spring进行管理
        // 不要关闭sqlSession
    }
}

    5) 配置dao

        把dao实现类配置到spring容器。

<bean id="userDao" class="com.jzfblog.mybatis.dao.impl.UserDaoImpl">
    <!-- 配置sqlSessionFactory -->
    <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

    6) 测试方法

public class UserDaoTest {
    private ApplicationContext context;
 
    @Before
    public void setUp() throws Exception {
        this.context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    }
 
    @Test
    public void testQueryUserById() {
        // 获取userDao
        UserDao userDao = this.context.getBean(UserDao.class);
 
        User user = userDao.queryUserById(1);
        System.out.println(user);
    }
 
    @Test
    public void testQueryUserByUsername() {
        // 获取userDao
        UserDao userDao = this.context.getBean(UserDao.class);
 
        List<User> list = userDao.queryUserByUsername("张");
        for (User user : list) {
            System.out.println(user);
        }
    }
 
    @Test
    public void testSaveUser() {
        // 获取userDao
        UserDao userDao = this.context.getBean(UserDao.class);
 
        User user = new User();
        user.setUsername("曹操");
        user.setSex("1");
        user.setBirthday(new Date());
        user.setAddress("三国");
        userDao.saveUser(user);
        System.out.println(user);
    }
}

5.Mapper代理形式开发dao

    1) 实现Mapper.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="com.jzfblog.mybatis.mapper.UserMapper">
    <!-- 根据用户id查询 -->
    <select id="queryUserById" parameterType="int" resultType="user">
        select * from user where id = #{id}
    </select>
 
    <!-- 根据用户名模糊查询用户 -->
    <select id="queryUserByUsername" parameterType="string"
        resultType="user">
        select * from user where username like '%${value}%'
    </select>
 
    <!-- 添加用户 -->
    <insert id="saveUser" parameterType="user">
        <selectKey keyProperty="id" keyColumn="id" order="AFTER"
            resultType="int">
            select last_insert_id()
        </selectKey>
        insert into user
        (username,birthday,sex,address) values
        (#{username},#{birthday},#{sex},#{address})
    </insert>
</mapper>

    2) 实现UserMapper接口

public interface UserMapper {
    /**
     * 根据用户id查询
     * 
     * @param id
     * @return
     */
    User queryUserById(int id);
 
    /**
     * 根据用户名模糊查询用户
     * 
     * @param username
     * @return
     */
    List<User> queryUserByUsername(String username);
 
    /**
     * 添加用户
     * 
     * @param user
     */
    void saveUser(User user);
}

    3) 配置mapper代理(方法一)

        在applicationContext.xml添加配置,MapperFactoryBean也是属于mybatis-spring整合包。

<!-- Mapper代理的方式开发方式一,配置Mapper代理对象 -->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
    <!-- 配置Mapper接口 -->
    <property name="mapperInterface" value="com.jzfblog.mybatis.mapper.UserMapper" />
    <!-- 配置sqlSessionFactory -->
    <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

    4) 测试方法

public class UserMapperTest {
    private ApplicationContext context;
 
    @Before
    public void setUp() throws Exception {
        this.context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    }
 
    @Test
    public void testQueryUserById() {
        // 获取Mapper
        UserMapper userMapper = this.context.getBean(UserMapper.class);
 
        User user = userMapper.queryUserById(1);
        System.out.println(user);
    }
 
    @Test
    public void testQueryUserByUsername() {
        // 获取Mapper
        UserMapper userMapper = this.context.getBean(UserMapper.class);
 
        List<User> list = userMapper.queryUserByUsername("张");
 
        for (User user : list) {
            System.out.println(user);
        }
    }
    @Test
    public void testSaveUser() {
        // 获取Mapper
        UserMapper userMapper = this.context.getBean(UserMapper.class);
 
        User user = new User();
        user.setUsername("曹操");
        user.setSex("1");
        user.setBirthday(new Date());
        user.setAddress("三国");
 
        userMapper.saveUser(user);
        System.out.println(user);
    }
}

    5) 扫描包形式配置mapper(方法二)

<!-- Mapper代理的方式开发方式二,扫描包方式配置代理 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!-- 配置Mapper接口 -->
    <property name="basePackage" value="com.jzfblog.mybatis.mapper" />
</bean>

        每个mapper代理对象的id就是类名,首字母小写。

打赏 蒋振飞

取消

感谢您的支持,我会继续努力的!

扫码支持
一分也是爱     一块不嫌多

点击 支付宝 或 微信 打赏蒋振飞

打开支付宝扫一扫,即可进行扫码打赏哦

评论列表