Mybatis(二):Mybatis使用

Java代码

    /*
     SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由对它进行清除或重建。
    使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次.
    因此 SqlSessionFactory 的最佳作用域是应用作用域。有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
      */

    private SqlSessionFactory sqlSessionFactory;

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

    从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。
    但是也可以使用任意的输入流(InputStream)实例,包括字符串形式的文件路径或者 file:// 的 URL 形式的文件路径来配置。
    MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,可使从 classpath 或其他位置加载资源文件更加容易。

    不使用 XML 构建 SqlSessionFactory
    见官网
     */
    @Before
    public void before() throws IOException {
        String resource = "mybatis/mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // SqlSessionFactoryBuilder
        // 这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。
        // 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void select() {
        /*
        依赖注入框架可以创建线程安全的、基于事务的 SqlSession 和映射器(mapper)并将它们直接注入到你的 bean 中,因此可以直接忽略它们的生命周期。
        每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
        绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。
        也绝不能将 SqlSession 实例的引用放在任何类型的管理作用域中,比如 Servlet 架构中的 HttpSession。

        每次收到的 HTTP 请求,就可以打开一个 SqlSession,返回一个响应,就关闭它。
        应该把这个关闭操作放到 finally 块中以确保每次都能执行关闭。
         */

        /*
        当Mybatis与一些依赖注入框架(如Spring或者Guice)同时使用时,SqlSessions将被依赖注入框架所创建,
        所以你不需要使用SqlSessionFactoryBuilder或者SqlSessionFactory
         */

        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {

            /*
            映射器是创建用来绑定映射语句的接口。映射器接口的实例是从 SqlSession 中获得的。
            因此从技术层面讲,映射器实例的最大作用域是和 SqlSession 相同的,因为它们都是从 SqlSession 里被请求的。

            映射器实例的最佳作用域是方法作用域。也就是说,映射器实例应该在调用它们的方法中被请求,用过之后即可废弃。并不需要显式地关闭映射器实例
             */

            UserDao dao = sqlSession.getMapper(UserDao.class);
            User user = dao.findById(2L);
            System.out.println(user);
        } finally {
            sqlSession.close();
        }
    }

    @Test
    public void add() {
        SqlSession sqlSession = sqlSessionFactory.openSession();

        User user = new User();
        user.setName("yangxuyue");
        user.setUsername("yang");
        user.setPassword("12345");
        user.setPhone("12345678901");
        user.setCreated(new Date());
        user.setModified(new Date());

        try {
            UserDao dao = sqlSession.getMapper(UserDao.class);
            dao.add(user);
            // 当进行添加/更新/删除的时候,sqlSession需要进行提交事务
            sqlSession.commit();

            // 返回主键,Mapper.xml上实现,有两种方式
            System.out.println(user.getId());
        } finally {
            sqlSession.close();
        }
    }

配置文件

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>
    <!--加载jdbc配置文件-->
    <properties resource="jdbc/jdbc.properties"/>
    <!--整合Spring后,environment不再被需要了-->
    <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.user}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 定义了 MyBatis 日志形式:输出到控制台 -->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <!--加载*Mapper.xml-->
    <mappers>
        <mapper resource="mybatis/UserMapper.xml"/>
    </mappers>
</configuration>

jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/demo?characterEncoding=utf-8&useSSL=false
jdbc.user=root
jdbc.password= 

UserMapper.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="chapter14_mybatis.UserDao">

    <!--
    每一个sql语句都会被封装为MappedStatement对象,*Mapper.xml以Statement为单位管理sql语句
    -->

    <!--映射-->
    <resultMap >
        <result column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="phone" property="phone"/>
        <result column="created" property="created"/>
        <result column="modified" property="modified"/>
    </resultMap>
    <parameterMap />
    <!--sql映射-->
    <sql >
        id, name, username, password, phone, created, modified
    </sql>

    <!--查询-->
    <select >
            parameterType="java.util.Map">
        SELECT
        <include ref>
        FROM user
        <where>
            <if test="id != null">
                AND id=#{id}
            </if>
            <if test="name != null">
                AND name=#{name}
            </if>
            <if test="username != null">
                AND username=#{username}
            </if>
            <if test="password != null">
                AND password=#{password}
            </if>
            <if test="phone != null">
                AND phone=#{phone}
            </if>
        </where>
    </select>

    <!--查询角色-->
    <select >
            parameterType="java.util.Map">
        SELECT r.*
        FROM user_l_role l,user u,role r
        WHERE l.user_id=u.id AND l.role_id=r.id
        <if test="userId != null">
            AND l.user_id=#{userId}
        </if>
    </select>

    <!--新增用户-->
    <!--返回主键-->
    <!--方式一-->
    <!--useGeneratedKeys="true" keyProperty="id">-->
    <!--useGeneratedKeys="true" 表示给主键设置自增长-->
    <!--keyProperty="id"  表示将自增长后的id赋值给实体类中的id字段。-->
    <!--方式二-->
    <!--<insert></insert> 中没有resultType属性,但是<selectKey></selectKey> 标签是有的。-->
    <!--order="AFTER" 表示先执行插入语句,之后再执行查询语句。-->
    <!--可被设置为 BEFORE 或 AFTER。-->
    <!--SELECT LAST_INSERT_ID() 表示MySQL语法中查询出刚刚插入的记录自增长Id.-->
    <!--实体类中uerId 要有getter() and setter(); 方法-->
    <insert >
        <selectKey resultType="java.lang.Long" order="AFTER" keyProperty="id">
            SELECT LAST_INSERT_ID()
        </selectKey>
        INSERT INTO user(name, username, password, phone, created, modified)
        VALUES (#{name},#{username},#{password},#{phone},#{created},#{modified})
    </insert>

    <!--根据id查询用户-->
    <select >
            resultMap="BaseResultMap">
        SELECT
        <include ref>
        FROM user
        WHERE id=#{id}
    </select>

    <!--更新用户-->
    <update >
        UPDATE user
        <set>
            <if test="name != null">
                name=#{name},
            </if>
            <if test="username != null">
                username=#{username},
            </if>
            <if test="password != null">
                password=#{password},
            </if>
            <if test="modified != null">
                modified=#{modified},
            </if>
            <if test="phone != null">
                phone=#{phone}
            </if>
        </set>
        WHERE id=#{id}
    </update>

    <!--删除用户-->
    <delete >
      DELETE FROM user
      WHERE id=#{id}
    </delete>

</mapper>