mybatis配置和使用

mybatis架构

强调内容

sqlMapConfig.xml 是核心配置文件
mapper.xml是映射文件,sql写在这里

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>
</configuration>

创建pojo

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


get/set……

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:命名空间,可以用于绑定接口,区分mapper文件 -->
<mapper namespace="test">
</mapper>

加载映射文件

<!-- 在MapConfig.xml中配置 -->
<mappers>
    <mapper resource="sqlmap/User.xml" />
</mappers>

根据id查询用户

<mapper namespace="test">

    <!-- id:statement的id 或者叫做sql的id-->
    <!-- parameterType:声明输入参数的类型 -->
    <!-- resultType:声明输出结果的类型,应该填写pojo的全路径 -->
    <!-- #{}:输入参数的占位符 -->
    <select id="queryUserById" parameterType="int"
        resultType="cn.test.mybatis.pojo.User">
        SELECT * FROM `user` WHERE id  = #{id}
    </select>

</mapper>

测试

public class MybatisTest {
    private SqlSessionFactory sqlSessionFactory = null;

    @Before
    public void init() throws Exception {
        // 1. 创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    // 2. 加载SqlMapConfig.xml配置文件
        InputStream in= Resources.getResourceAsStream("SqlMapConfig.xml");

        // 3. 创建SqlSessionFactory对象
        this.sqlSessionFactory = sqlSessionFactoryBuilder.build(in);
    }

//或者直接写成
//String resource = "sqlMapConfig.xml";
//InputStream in = Resource.getResourceAsStream(resource);
//SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
//SqlSession sqlSession = sqlSessionFactory.openSession()'

    @Test
    public void testQueryUserById() throws Exception {
        // 4. 创建SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        // 5. 执行SqlSession对象执行查询,获取结果User
        // 第一个参数是User.xml的statement的id,第二个参数是执行sql需要的参数;
        Object user = sqlSession.selectOne("test.queryUserById", 1);

        // 6. 打印结果
        System.out.println(user);

        // 7. 释放资源
        sqlSession.close();
    }
}

根据用户名模糊查询用户

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

或者

    <!-- resultType的配置和返回一个结果的配置一样 -->
<select id="queryUserByUsername2" parameterType="string"
        resultType="cn.test.mybatis.pojo.User">
        SELECT * FROM `user` WHERE username LIKE '%'#{value}'%'
    </select>
<!-- ${} 字符串拼接,#{}是占位符,自动进行java类型和jdbc类型转换,#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
而${}不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。 -->

测试

// 5. 执行SqlSession对象执行查询,获取结果User
    // 查询多条数据使用selectList方法
    List<Object> list = sqlSession.selectList("test.queryUserByUsername2", "王");

5.7. 实现添加用户

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

测试

//   执行SqlSession对象执行保存
    // 创建需要保存的User
    User user = new User();
    user.setUsername("aa");
    user.setSex("1");
    user.setBirthday(new Date());
    user.setAddress("bb");

    sqlSession.insert("test.saveUser", user);
    System.out.println(user);

    // 需要进行事务提交
    sqlSession.commit();

    // 7. 释放资源
    sqlSession.close();

5.7.4. mysql自增主键返回
LAST_INSERT_ID():是mysql的函数,返回auto_increment自增列新记录id值。

!-- 保存用户 -->
<insert id="saveUser" parameterType="cn.test.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>

5.8. 修改用户

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

测试

//  执行SqlSession对象执行更新
    // 创建需要更新的User
    User user = new User();
    user.setId(26);
    user.setUsername("关羽");
    user.setSex("1");
    user.setBirthday(new Date());
    user.setAddress("蜀国");

    sqlSession.update("test.updateUserById", user);

删除用户

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

测试

// 5. 执行SqlSession对象执行删除
        sqlSession.delete("test.deleteUserById", 48);

Mapper动态代理方式

Mapper接口开发需要遵循以下规范:
1、 Mapper.xml文件中的namespace与mapper接口的类路径相同。
2、 Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
3、 Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
4、 Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

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();
    }

动态代理的方式,由sqlSession帮我们动态生成一个实现类,这种方式,sqlSession会根据返回值选择使用selectOne还是selectList

SqlMapConfig.xml配置文件

properties(属性)

<!-- 使用resource属性加载外部配置文件 -->
    <properties resource="db.properties">

typeAliases(类型别名)

<typeAliases>
        <!-- 单个别名定义 -->
        <typeAlias alias="user" type="cn.test.mybatis.pojo.User" />
        <!-- 批量别名定义,扫描整个包下的类,别名为类名(大小写不敏感) -->
        <package name="cn.test.mybatis.pojo" />
        <package name="其它包" />
    </typeAliases>

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

mappers(映射器)

<mapper resource=" " />
//使用相对于类路径的资源(现在的使用方式)
    <mapper resource="sqlmap/User.xml" />
<mapper class=" " />
//使用mapper接口类路径
    <mapper class="cn.test.mybatis.mapper.UserMapper"/>

//注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
<package name=""/>
//注册指定包下的所有mapper接口
    <package name="cn.test.mybatis.mapper"/>
//注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

如果输入类型时vo包装类

#{}中应该填写包装类中属性对象中的属性

#{user.name}

输出resultMap(输出类型)

用于查询字段和pojo属性名不一致,用resultMap手动映射

<resultMap type="Orders" id="orders">
    <id colunm="数据库表字段" property="pojo属性"/> //id映射
    <result column="数据库表字段" property="pojo属性"/> //其他字段映射
    //单表时,可以只手动映射名字不一样的字段
</resultMap>
<select id="selectOrdersList" resultMap="roders">
    select id,user_id,number from orders
</select>

动态sql

通过mybatis提供的各种标签实现动态拼接sql

<select id="selectUserBySexAndUsername" parameterType="user" resultType="User">
    select * from user 
    <where>
        <if test="sex!=null and sex!=''">
            sex = #{sex} 
        </if>
        <if test="username !=null and username !=''">
            AND username LIKE
            '%${username}%'

        </if>
</select>

where标签可以去除第一个and
防止sql出现AND username LIKE..的情况

sql片段
多次出现的重复部分,提取共用

<sql id="selector">
    select * from user 
</sql>
<include refid="selector"/>

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

QueryVo

<!-- 根据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>

测试

// 使用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);

遍历数组

<where>
    <include refid="  ">
    <where>
        <foreach collection="Array" ...>
        //list只需将Array换成List
        <foreach collection="List" ...>

多表关联查询

一对一查询

可以使用resultType或者resultMap
resultType需要在pojo类中加上所需要的字段
resultMap加入所需要的对象属性

resultMap
如 在Order类中加入User属性,user属性中用于存储关联查询的用户信息,因为订单关联查询用户是一对一关系,所以这里使用单个User对象存储关联查询的用户信息。

<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>

测试

// 使用userMapper执行根据条件查询用户
    List<Order> list = userMapper.queryOrderUserResultMap();

一对一查询时,resultMap中配置的映射不能省略,否则会映射不到

一对多查询

案例:查询所有用户信息及用户关联的订单信息。
用户信息和订单信息为一对多关系。
在User类中加入List orders属性

<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>

测试

// 使用userMapper执行根据条件查询用户
    List<User> list = userMapper.queryUserOrder();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值