SSM—MyBatis总结


1.CRUD

在MyBatis框架下进行CRUD就十分简单了,只需要两步:

  • 1.在UserMapper.xml映射文件中写sql语句
  • 2.编写测试代码

映射文件

<mapper namespace="UserMapper">
<!--    resultType="com.kk.demo1.User"表明sql语句查询的结果封装到User实体类中-->
    <select id="findAll" resultType="com.kk.demo1.User">
        select * from users
    </select>

<!--    插入操作,将User对象的属性插入表中,parameterType="要插入的数据类型"
        注意#{id}对应的是 User对象的第一个属性名,不是数据库的字段名
-->
    <insert id="add" parameterType="com.kk.demo1.User">
        insert into users values(#{id},#{username},#{password})
    </insert>

<!--    修改操作-->
    <update id="update" parameterType="com.kk.demo1.User">
        update users set username=#{username},password=#{password} where id=#{id}
    </update>

<!--    删除操作,这里直接写int可以成功是因为MyBatis为Integer设置好了别名int,相应的String——string,Boolean——boolean等-->
    <delete id="del" parameterType="int">
    	delete from users where id=#{id}
    </delete>
</mapper>

测试代码

@Test
    public void test() throws IOException {
        //获得核心配置文件,注意不要导错包import org.apache.ibatis.io.Resources
        InputStream sqlMapConfig = Resources.getResourceAsStream("SqlMapConfig.xml");
        //获得session工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(sqlMapConfig);
        //获得session(会话)对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //执行sql语句,只有这里会变
//        //1.查询
//        List<User> list = sqlSession.selectList("UserMapper.findAll");
//        System.out.println(list);

//        //2.插入
//        User user = new User();
//        //user.setId(4);
//        user.setUsername("kk");
//        user.setPassword("123");
//        sqlSession.insert("UserMapper.add",user);
//        //MyBatis默认是不提交事务的,因此执行更新操作(增删改)时需要提交事务
//        sqlSession.commit();

//        //3.修改
//        User user = new User();
//        user.setId(3);
//        user.setUsername("kk");
//        user.setPassword("123");
//        sqlSession.update("UserMapper.update",user);
//        sqlSession.commit();

        //4.删除,当多条件判断时仍需要传入User对象
        sqlSession.delete("UserMapper.del",4);
        sqlSession.commit();

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

2.MyBatis类的分析

  • SqlSessionFactoryBuilder.build(InputStream)
    前面我们写过如下代码:
    //通过Resources类 将MyBatis核心文件加载为输入流,以此构建SqlSessionFactory工厂对象
    InputStream sqlMapConfig = Resources.getResourceAsStream("SqlMapConfig.xml");
    //获得session工厂对象
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(sqlMapConfig);
    /*
    1.Mybatis读取XML配置文件后会将内容放在一个Configuration类中
    SqlSessionFactoryBuilder会读取Configuration类中信息创建SqlSessionFactory
    2.初始化SqlSessionFactory时,Mapper 接口进行注册,
    注册在了名为 MapperRegistry 类的 HashMap中,key = Mapper class, value = 当前创建的Mapper的工厂
    */
    
  • SqlSessionFactory,用来创建一个SqlSession对象(类似于JDBC中的Connection类),用来和数据库交互
    • openSession() 默认开启一个事务(即创建sqlSession对象),但不会自动提交,要通过sqlSession.commit()手动提交
    • openSession(boolean autoCommit) 参数设为true则会自动提交事务
  • SqlSession对象,可以执行sql语句和操作事务
    • < T> T selectOne(“sql语句位置”,参数(对象或基本数据类型)) 返回查询到的一个结果
    • < T> T selectList(“sql语句位置”,参数) 返回查询的数组
    • int insert(“sql语句位置”,参数)
    • int update(“sql语句位置”,参数)
    • int delete(“sql语句位置”,参数)
    • void commit() 提交事务
    • void rollback() 回滚

3.动态代理实现Dao层

应当注意名称的一致性,否则会出现找不到类等错误
在这里插入图片描述
动态代理

UserDao userDao = sqlSession.getMapper(UserDao.class);
//userdao.method
//获取对应的Mapper,让映射器通过命名空间和方法名称找到对应的SQL,发送给数据库执行

4.映射文件详解(动态sql和sql片段抽取)

UserDao接口中新添两个方法

public interface UserDao {
    public List<User> findAll() throws IOException;
    public List<User> findByCondition(User user) throws IOException;
    public List<User> findByIds(List<Integer> ids) throws IOException;
}

在映射文件中编写动态sql并抽取相同的sql片段

<mapper namespace="com.kk.dao.UserDao">
<!--    sql语句抽取-->
    <sql id="selectUser">select * from users</sql>
    
    <select id="findByCondition" parameterType="user" resultType="user">
        <include refid="selectUser"></include>
        <where>
            <if test="id!=0">
                and id=#{id}
            </if>
            <if test="username!=null">
                and username=#{username}
            </if>
            <if test="password!=null">
                and password=#{password}
            </if>
        </where>
    </select>

<!--    List->list 如果传入的是数组参数类型应写array-->
    <select id="findByIds" parameterType="list" resultType="user">
--         相当于select * from users where id in() 或 id=1 or id=2...
        <include refid="selectUser"></include>
        <where>
            <foreach collection="list" open="id in(" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </where>
    </select>
</mapper>

5.核心配置文件详解

5.1 标签简介

  • properties 加载外部properties文件
  • typeAliases 设置类型别名
  • environments 配置数据源环境
  • typeHandler 配置自定义类型处理器,将数据库的jdbc类型和java中的类型进行相互转换https://cloud.tencent.com/developer/article/1549181
  • plugins 配置插件

5.2 抽取数据库信息为.properties文件

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>
<!--    加载properties文件-->
    <properties resource="jdbc.properties"/>

<!--    定义别名-->
    <typeAliases>
        <typeAlias type="com.kk.demo1.User" alias="user"/>
    </typeAliases>
    
<!--    数据源环境,默认情况下使用id="mysql"环境-->
    <environments default="mysql">
        <environment id="mysql">
            <!--transactionManager事务管理器:JDBC——可以使用提交和回滚,依赖于connection来管理事务;MANAGED——让容器来管理事务的生命周期,默认会关闭连接-->
            <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/kk/mapper/UserMapper.xml"/>
    </mappers>
</configuration>

jdbc.properties

jdbc.driver = com.mysql.cj.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
jdbc.username = root
jdbc.password = root

在这里插入图片描述

最后,标签的书写顺序是有规定的
在这里插入图片描述

6.多表操作

6.1一对一查询

新建两个数据库表(orders和users),一对一查询即一个订单对应一个用户
在这里插入图片描述
Order实体类

public class Order {
    private int id;
    private Date ordertime;
    private double total;
    //表示当前订单属于哪个用户
    private User user;
    //别忘了在核心配置文件中起别名 <typeAlias type="com.kk.demo1.Order" alias="order"/>,方便后续操作

OrderDao接口,这里仍使用动态代理实现

public interface OrderDao {
    public List<Order> findAll() throws IOException;
}

编写sql语句以及如何将查询结果进行封装

<mapper namespace="com.kk.dao.OrderDao">

<!--    这里type="order"(表示该映射将封装到order中)正确,是因为在核心配置文件中设置了别名-->
    <resultMap id="orderMap" type="order">
<!--        指定 字段(column) 和对象属性(property) 映射关系-->
        <id column="oid" property="id"/>
        <result column="ordertime" property="ordertime"/>
        <result column="total" property="total"/>
<!-- 对象封装方式-->
<!-- 封装方式1-->
<!--        <result column="uid" property="user.id"/>-->
<!--        <result column="username" property="user.username"/>-->
<!--        <result column="password" property="user.password"/>-->

<!-- 封装方式2     property指order中的属性名称(user), javaType指order中的属性类型(User)-->
        <association property="user" javaType="user">
            <result column="uid" property="id"/>
            <result column="username" property="username"/>
            <result column="password" property="password"/>
        </association>
    </resultMap>

    <select id="findAll" resultMap="orderMap">
        select *,o.id oid from `orders` o,`users` u where o.uid=u.id
    </select>

SqlYog中查询结果
在这里插入图片描述
测试结果,代码与之前类似,不再赘述
在这里插入图片描述

6.2一对多查询

一对多查询即一个用户可以有多个订单

在User实体类中添加存储Order的集合

public class User {
    private int id;
    private String username;
    private String password;
    private List<Order> orderList;
}

编写sql语句以及如何将查询结果进行封装

    <resultMap id="userMap" type="user">
        <id column="uid" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
<!--        集合的配置 property指集合名称,ofType指集合中的数据类型-->
        <collection property="orderList" ofType="order">
<!--            封装order属性-->
            <id column="oid" property="id"/>
            <result column="ordertime" property="ordertime"/>
            <result column="total" property="total"/>
        </collection>
    </resultMap>
    <select id="findOneToMore" resultMap="userMap">
        select *,o.id oid from users u, orders o where u.id=o.uid
    </select>

测试结果
在这里插入图片描述

6.3多对多查询

如下,创建三个表(这里例子举得不太恰当,用户不可能即是经理又是职员…)
在这里插入图片描述
新增实体类Role

public class Role {
    private int id;
    private String roleName;
}

在User实体类中添加存储Role的集合

public class User {
    private int id;
    private String username;
    private String password;
    private List<Order> orderList;
    private List<Role> roleList;
}

编写sql语句以及如何将查询结果进行封装

    <resultMap id="user_roleMap" type="user">
        <id column="user_id" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <collection property="roleList" ofType="role">
            <id column="role_id" property="id"/>
            <result column="rolename" property="roleName"/>
        </collection>
    </resultMap>
    <select id="findMoreToMore" resultMap="user_roleMap">
        SELECT * FROM users u,`user_role` ur,`role` r WHERE u.id=ur.user_id AND ur.role_id=r.id
    </select>

测试结果
在这里插入图片描述

7.注解的使用

使用注解就不需要再写映射文件了,可以简化很多操作

7.1 CRUD

定义接口,使用注解进行sql语句的编写

public interface UserMapper {
    @Insert("insert into users values(#{id},#{username},#{password})")
    public void insert(User user);
    @Update("update users set username=#{username},password=#{password} where id=#{id}")
    public void update(User user);
    @Delete("delete from users where id=#{id}")
    public void del(int id);
    @Select("select * from users where id=#{id}")
    public User findById(int id);
    @Select("select * from users")
    public List<User> findAll();
}

注意,虽然不用加载映射文件了,但仍需要在核心配置文件中添加映射关系

<!--    使用注解不用加载映射文件,但仍需要加载映射关系(因为映射关系始终存在)-->
    <mappers>
<!--        指定接口UserMapper所在的包-->
        <package name="com.kk.mapper"/>
    </mappers>

测试代码,只列举一个

public class TestAnno {
    private UserMapper userMapper;
    @Before
    public void before() throws IOException {
        InputStream sqlMapConfig = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(sqlMapConfig);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        userMapper = sqlSession.getMapper(UserMapper.class);
    }
    @Test
    public void add(){
        User user = new User();
        user.setUsername("kk");
        user.setPassword("123");
        userMapper.insert(user);
    }
}

7.2 一对一查询@One

一个订单对应一个用户
实现方式1

public interface OrderMapper {
    @Select("select *,o.id oid from `orders` o,`users` u where o.uid=u.id")
    @Results({
            @Result(column = "oid", property = "id"),
            @Result(column = "ordertime", property = "ordertime"),
            @Result(column = "total", property = "total"),
            @Result(column = "uid", property = "user.id"),
            @Result(column = "username", property = "user.username"),
            @Result(column = "password", property = "user.password")
    })
    public List<Order> findAll();
}

实现方式2

public interface OrderMapper {
    @Select("select * from orders")
    @Results({
            @Result(column = "id", property = "id"),
            @Result(column = "ordertime", property = "ordertime"),
            @Result(column = "total", property = "total"),
            @Result(
                    property = "user", //要封装的属性名
                    column = "uid", //根据此字段再次查询users表
                    javaType = User.class, //要封装的实体类型
                    //@One代替了assocation标签,指定查询返回的单一对象
                    //这里不能写sql语句,而是调用UserMapper接口中的方法
                    //格式:@Result(column="",property="",one=@One(select=""))
                    one = @One(select = "com.kk.mapper.UserMapper.findById")
            )
    })
    public List<Order> findAll();
}

测试结果
在这里插入图片描述

7.3 一对多查询@Many

一个用户可能有多个订单
UserMapper接口

//一对多查询
  @Select("select * from users")
  @Results({
          @Result(id = true,column = "id",property = "id"),
          @Result(column = "username",property = "username"),
          @Result(column = "password",property = "password"),
          @Result(
                  property = "orderList",
                  column = "id",
                  javaType = List.class,
                  many = @Many(select = "com.kk.mapper.OrderMapper.findByUid")
          )
  })
  public List<User> findOneToMore();

在OrderMapper接口中新添

   @Select("select * from orders where uid=#{uid}")
   public List<Order> findByUid(int uid);

测试结果
在这里插入图片描述

7.4 多对多查询

仍是这个案例
在这里插入图片描述
UserMapper接口

//多对多查询
 @Select("select * from users")
 @Results({
         @Result(id = true,column = "id",property = "id"),
         @Result(column = "username",property = "username"),
         @Result(column = "password",property = "password"),
         @Result(
                 property = "roleList",
                 column = "id", //以users表中的字段id再次进行查询
                 javaType = List.class,
                 many = @Many(select = "com.kk.mapper.RoleMapper.findByUserId")
         )
 })
 public List<User> findMoreToMore();

新增RoleMapper接口

public interface RoleMapper {
    @Select("select * from `user_role` ur,`role` r WHERE ur.user_id=#{uid} AND ur.role_id=r.id")
    public List<Role> findByUserId(int uid);
}

测试结果
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值