5/13day53_注解&分页综合练习

回顾

1. 嵌套查询
    将多表的联合,拆成多个单表查询,在通过mybatis嵌套组合
    步骤:一对一举例
        1)根据订单id查询订单
        2)根据订单uid查询用户
        3)最后由mybatis嵌套组合
2. 加载策略
    模型在关联时,是否要查询所管理的数据模型
    立即加载:一对一
    延迟加载:一对多、多对多

3. 缓存机制
    提高查询效率
    一级缓存:不需要我们做任何配置,底层就是map集合
    二级缓存:需要在映射文件配置<cache></cache> ,给实体类实现序列化接口【了解】

4. 核心配置文件回顾
    所有的配置文件,每一个标签必须加中文注释...

MyBatis注解&综合练习

今日目标

1. 注解开发
    单表【重点】
    多表【了解】
    
2. 综合案例练习
    查询所有
    分页查询【重点:3遍】

一 MyBatis注解

​ 这几年来注解开发越来越流行,Mybatis也可以使用注解开发方式,这样我们就可以减少编写Mapper映射文件了。我们先围绕一些基本的CRUD来学习,再学习复杂映射多表操作。

1.1 MyBatis常用注解

* @Insert:实现新增,代替了<insert></insert>
 
* @Update:实现更新,代替了<update></update>

* @Delete:实现删除,代替了<delete></delete>

* @Select:实现查询,代替了<select></select>

* @Result:实现结果集封装,代替了<result></result>

* @Results:可以与@Result 一起使用,封装多个结果集,代替了<resultMap></resultMap>

* @One:实现一对一结果集封装,代替了<association></association>
 
* @Many:实现一对多结果集封装,代替了<collection></collection>

环境搭建

1589332825508.png

1.2 MyBatis单表操作【重点】

需求:基于user模块通过注解实现,增删改查

① UserMapper接口

public interface UserMapper {

    // 查询所有
    @Select("select id as uid,username as uname,birthday as bir , sex as gender, address as addr from user")
    @Results({ // resultMap标签手动映射
            @Result(column = "uid",property = "id",id=true), // result标签映射封装
            @Result(column = "uname",property = "username"),
            @Result(column = "bir",property = "birthday"),
            @Result(column = "gender",property = "sex"),
            @Result(column = "addr",property = "address")
    })
    public List<User> findAll();

    // id查询
    @Select("select * from user where id = #{id}")
    public User findById(Integer id);


    // 新增
    @Insert("insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})")
    public void save(User user);


    // 修改(动态sql还是推荐使用xml)
    @Update("update user set username = #{username}, birthday = #{birthday}, sex = #{sex}, address = #{address} where id = #{id}")
    public void update(User user);


    // 删除
    @Delete("delete from user where id = #{id}")
    public void delete(Integer id);
}

② 测试

public class UserMapperTest extends BaseMapperTest {

    // 单表测试
    @Test
    public void test01() throws Exception {
        // 获取代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        // 查询所有
        List<User> list = userMapper.findAll();
        System.out.println(list);

       // 查询一个
       /* User user = userMapper.findById(41);
        System.out.println(user);*/

       // 新增
       /* User user = new User();
        user.setUsername("吉克隽逸");
        user.setBirthday(new Date());
        user.setSex("女");
        user.setAddress("彝族....");

        userMapper.save(user);*/

       // 更新
       /* User user = new User();
        user.setId(53);
        user.setUsername("迪丽热巴");
        user.setBirthday(new Date());
        user.setSex("女");
        user.setAddress("新疆....");
        userMapper.update(user);*/


       // 删除
       // userMapper.delete(53);
    }

}

1.3 MyBatis多表操作【了解】

注解多表操作是基于嵌套查询来实现

1589334124076.png

1.3.1 一对一查询

需求:查询一个订单,与此同时查询出该订单所属的用户

一对一查询语句

SELECT * FROM orders where id = #{id};
SELECT * FROM `user` WHERE id = #{订单的uid};

① OrderMapper接口

public interface OrderMapper {


    // 一对一嵌套注解
    @Select("select * from orders where id = #{id}")
    @Results({
            @Result(column = "id",property = "id",id=true),
            @Result(column = "ordertime",property = "ordertime"),
            @Result(column = "money",property = "money")
    })
    public Order findByIdWithUser(Integer id);
}

② UserMapper接口

public interface UserMapper {

    // id查询
    @Select("select * from user where id = #{id}")
    public User findById(Integer id);
}

③ 注解嵌套

1589334818010.png

④ 测试

public class OrderMapperTest extends BaseMapperTest { // 继承父类,就可以直接使用 父类的方法和成员变量了

    // 一对一嵌套测注解试
    @Test
    public void test01() throws Exception {
        // 获取代理对象
        OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);

        // 根据id查询
        Order order = orderMapper.findByIdWithUser(1);
       System.out.println(order);
    }
}

1.3.2 一对多查询

需求:查询一个用户,与此同时查询出该用户具有的订单

一对多查询语句

SELECT * FROM `user` where id = #{id};
SELECT * FROM orders where uid = #{用户id};

① UserMapper接口

public interface UserMapper {

    // 一对多注解嵌套查询
    @Select("select * from user where id = #{id}")
    @Results({ // resultMap标签手动映射
            @Result(column = "id",property = "id",id=true), // result标签映射封装
            @Result(column = "username",property = "username"),
            @Result(column = "birthday",property = "birthday"),
            @Result(column = "sex",property = "sex"),
            @Result(column = "address",property = "address")
    })
    public User findByIdWithOrders(Integer id);
}

② OrderMapper接口

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

③ 注解嵌套

1589336198179.png

④ 测试

// 一对多注解测试
@Test
public void test02() throws Exception {
    // 获取代理对象
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

    User user = userMapper.findByIdWithOrders(41);
    System.out.println(user);
    System.out.println(user.getOrderList());
}

1.3.3 多对多查询

需求:查询用户同时查询出该用户的所有角色

多对多查询语句

SELECT * FROM `user` where id = #{id};
SELECT * FROM role r INNER JOIN user_role ur ON r.`id` = ur.`rid` 
    WHERE ur.`uid` = #{用户id};

① UserMapper接口

public interface UserMapper {


    // 多对多注解嵌套查询
    @Select("select * from user where id = #{id}")
    @Results({ // resultMap标签手动映射
            @Result(column = "id",property = "id",id=true), // result标签映射封装
            @Result(column = "username",property = "username"),
            @Result(column = "birthday",property = "birthday"),
            @Result(column = "sex",property = "sex"),
            @Result(column = "address",property = "address")
    })
    public User findByIdWithRoles(Integer id);
}

② RoleMapper接口

public interface RoleMapper {

    
    @Select("SELECT * FROM role r INNER JOIN user_role ur ON ur.`rid` = r.`id` WHERE ur.`uid` =#{uid}")
    @Results({
            @Result(column = "id",property = "id",id=true),
            @Result(column = "role_name",property = "roleName"),
            @Result(column = "role_desc",property = "roleDesc")
    })
    public List<Role> findByUid(Integer uid);
}

③ 注解嵌套

1589336851156.png

④ 测试

// 多对多注解测试
@Test
public void test03()throws Exception{
    // 获取代理对象
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

    User user = userMapper.findByIdWithRoles(41);
    System.out.println(user);
    System.out.println(user.getRoleList());
}

1.4 局部延迟加载

不管是一对多还是多对多 ,在注解配置中都有fetchType的属性

* fetchType = FetchType.LAZY    表示懒加载

* fetchType = FetchType.EAGER   表示立即加载

* fetchType = FetchType.DEFAULT 表示使用全局配置

1.5 二级缓存

配置SqlMapConfig.xml文件开启二级缓存的支持

<settings>
    <!--
        因为cacheEnabled的取值默认就为true,所以这一步可以省略不配置。
        为true代表开启二级缓存;为false代表不开启二级缓存。
    -->
    <setting name="cacheEnabled" value="true"/>
</settings>

在Mapper接口中使用注解配置二级缓存

@CacheNamespace
public interface UserMapper {...}
1589337040594.png

1.6 知识小结

1. 注解开发和xml配置相比,从开发效率来说,注解编写更简单,效率更高。

2. 从可维护性来说,注解如果要修改,必须修改源码,会导致维护成本增加。xml维护性更强。

* 经验:单表简单CRUD可以使用注解、多表及动态sql你就用xml

二 MyBatis案例练习

2.1 编程风格

浏览器:Chrome、Firefox

包目录:cn(com).公司名.项目名(都是小写)

类:大驼峰式命名

方法名:小驼峰式命名

帅哥用啥你用啥,帅哥写啥你写啥

2.2 环境搭建

① 准备数据库和表

1589337903879.png

② 创建web工程,导入jar包

1589338008633.png

③ 导入页面资源

1589338054431.png

④ 创建三层包结构

1589338179795.png

⑤ 导入mybatis相关初始化配置

1589338300300.png

⑥ 编写中文过滤器

@WebFilter("/*")
public class EncodeFilter implements Filter {

    public void init(FilterConfig config) throws ServletException {

    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException {
        // 接收请求字符集
        servletRequest.setCharacterEncoding("utf-8");
        
        // 放行
        chain.doFilter(servletRequest, servletResponse);
    }

    public void destroy() {

    }

}

⑦ 测试环境

2.3 查询所有

2.3.1 需求和效果实现

通过三层架构+接口+mybatis,查询员工信息,在页面展示

1589339224995.png

2.3.2 需求分析

1589339710436.png

2.3.3 代码实现

1589340100662.png

① index.jsp

<a href="${pageContext.request.contextPath}/EmpServlet?action=findAll">员工列表</a>

② Emp实体类

public class Emp {
    
    private Integer id;
    
    private String ename;
    
    private String sex;
    
    private String joindate; // 通过字符串也可以表示日期
    
    private Double salary;
    
    private String address;
}

③ EmpServlet

@WebServlet("/EmpServlet")
public class EmpServlet extends HttpServlet {

    // 重写service方法
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取action请求参数
        String action = request.getParameter("action");
        // 判断
        if (action.equals("findAll")) {
            this.findAll(request, response);
        }
    }

    // 查询所有
    protected void findAll(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.调用service查询
        EmpService empService = new EmpServiceImpl();
        List<Emp> list = empService.findAll();
        // 2.将list写入request域
        request.setAttribute("list", list);
        // 3.转发
        request.getRequestDispatcher("/list.jsp").forward(request, response);
    }
}

④ EmpServiceImpl

public class EmpServiceImpl implements EmpService {

    @Override
    public List<Emp> findAll() {
        // 通过mybatis工具类获取sqlSession
        SqlSession sqlSession = MyBatisUtils.openSession();
        // 创建EmpDao代理对象
        EmpDao empDao = sqlSession.getMapper(EmpDao.class);
        // 查询
        List<Emp> list= empDao.findAll();
        // 关闭sqlSession
        MyBatisUtils.close(sqlSession);
        return list;
    }
}

⑤ EmpDao(接口+映射)

1589340671696.png
1589341028132.png
1589341076131.png

⑥ list.jsp

<c:forEach items="${list}" var="emp">
    <tr>
        <td>${emp.id}</td>
        <td>${emp.ename}</td>
        <td>${emp.joindate}</td>
        <td>${emp.salary}</td>
        <td>${emp.address}</td>
    </tr>
</c:forEach>

2.4 分页查询【重点☆☆☆☆】

2.4.1 导入数据

insert  into `emp`(`id`,`ename`,`sex`,`joindate`,`salary`,`address`) values(6,'王昭君','女','2010-12-17',28500,'北京'),(7,'刘备','男','2014-07-18',24500,'广州'),(8,'小二郎','男','2004-11-23',30000,'广州'),(9,'小龙女','女','2009-05-18',50000,'深圳'),(10,'貂蝉','女','2014-07-30',15000,'深圳'),(11,'刘三','男','2019-06-23',11000,'上海'),(12,'李逵','男','2012-07-05',9500,'广州'),(13,'李楠','女','2012-07-05',11500,'北京'),(14,'小白龙','男','2011-09-18',30000,'深圳'),(15,'西施','女','2015-07-06',13000,'北京'),(16,'刘茹','女','2019-08-07',6000,'北京');

2.4.2 分页介绍

在实际开发中,如果数据库数据太多,一般我们需要进行分页查询,提高效率...

分页技术实现

物理分页:数据库实现(MySQL、Oracle)

内存分页:查询全部,在通过java代码进行分页

今天我们来使用MySQL操作物理分页

* 语法:
        select * from 表名 limit 开始索引,每页个数;
        
* 模拟百度分页,一个显示5条,数据库共有16条记录
    第一页
        select * from 表名 limit 0,5;
    第二页
        select * from 表名 limit 5,5;
    第三页
        select * from 表名 limit 10,5;
    第四页
        select * from 表名 limit 15,5;
        
* 索引公式
        开始索引=(当前页-1) × 每页个数
        
* 如何获得当前页和每页个数?
        前端页提供的

2.4.3 需求和效果实现

通过mysql物理分页,一个显示5条,数据库共有16条记录

1589341995477.png

2.4.3 需求分析

1589342693907.png

后端代码流程图

1589350595261.png

2.4.4 代码实现

① index.jsp

1589350778119.png

② PageBean

public class PageBean<E> {
    
    private Integer totalCount; // 总记录数

    private Integer totalPage;// 总页数

    private List<E> list; // 结果集

    private Integer currentPage; // 当前页

    private Integer pageSize; // 每页个数

}

③ EmpServlet

1589351273546.png
    EmpService empService = new EmpServiceImpl();

    // 分页查询
    protected void findByPage(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.接收请求参数
        String currentPageStr = request.getParameter("currentPage");
        String pageSizeStr = request.getParameter("pageSize");

        // 2.转为整型
        int currentPage = Integer.parseInt(currentPageStr);
        int pageSize = Integer.parseInt(pageSizeStr);

        // 3.调用service查询
        PageBean<Emp> pb = empService.findByPage(currentPage, pageSize);

        // 4.设置到request域
        request.setAttribute("pb", pb);

        // 5.转发
        request.getRequestDispatcher("/list.jsp").forward(request, response);
    }

④ EmpServiceImpl

@Override
public PageBean<Emp> findByPage(int currentPage, int pageSize) {
    // 通过mybatis工具类获取sqlSession
    SqlSession sqlSession = MyBatisUtils.openSession();
    // 创建EmpDao代理对象
    EmpDao empDao = sqlSession.getMapper(EmpDao.class);

    // 1.创建 PageBean
    PageBean<Emp> pageBean = new PageBean<>();

    // 2.封装当前页和每页个数
    pageBean.setCurrentPage(currentPage);
    pageBean.setPageSize(pageSize);

    // 3.调用dao查询总记录数并封装
    Integer totalCount = empDao.findCount();
    pageBean.setTotalCount(totalCount);

    // 4.计算并封装总页数
    int totalPage = (int)Math.ceil(totalCount * 1.0/ pageSize);
    pageBean.setTotalPage(totalPage);

    // 5.计算开始索引
    int index = (currentPage - 1) * pageSize;

    // 6.调用dao查询结果集并封装
    List<Emp> list = empDao.findList(index,pageSize);
    pageBean.setList(list);
    // 关闭sqlSession
    MyBatisUtils.close(sqlSession);
    // 7.返回pageBean对象
    return pageBean;
}

⑤ EmpDao(接口+映射)

1589352386073.png
1589352398163.png

⑥ list.jsp

1589352796689.png
<body>
<table border="1" cellpadding="0" cellspacing="0" width="600px">
    <tr>
        <td>姓名</td>
        <td>性别</td>
        <td>入职日期</td>
        <td>薪资</td>
        <td>住址</td>
    </tr>
    <c:forEach items="${pb.list}" var="emp">
        <tr>
            <td>${emp.id}</td>
            <td>${emp.ename}</td>
            <td>${emp.joindate}</td>
            <td>${emp.salary}</td>
            <td>${emp.address}</td>
        </tr>
    </c:forEach>
</table>
<table>
    <tr>
        <td style="text-align: left">总共检索到${pb.totalCount}条记录,共分${pb.totalPage}页</td>
    </tr>
</table>
<table id="page">
    <tr>
            <c:if test="${pb.currentPage>1}">
                 <td style="width:50px">
                    <a style="text-decoration: none" href="${pageContext.request.contextPath}/EmpServlet?action=findByPage&currentPage=${pb.currentPage-1}&pageSize=5">上一页</a>
                </td>
            </c:if>
        <c:forEach begin="1" end="${pb.totalPage}" var="page">
            <c:if test="${page == pb.currentPage}">
                <td bgcolor="#ffd700">
                    <a style="text-decoration: none" href="${pageContext.request.contextPath}/EmpServlet?action=findByPage&currentPage=${page}&pageSize=5">${page}</a>
                </td>
            </c:if>
            <c:if test="${page != pb.currentPage}">
                <td>
                    <a style="text-decoration: none" href="${pageContext.request.contextPath}/EmpServlet?action=findByPage&currentPage=${page}&pageSize=5">${page}</a>
                </td>
            </c:if>

        </c:forEach>
        <c:if test="${pb.currentPage < pb.totalPage}">
            <td style="width:50px">
                <a style="text-decoration: none" href="${pageContext.request.contextPath}/EmpServlet?action=findByPage&currentPage=${pb.currentPage+1}&pageSize=5">下一页</a>
            </td>
        </c:if>
    </tr>
</table>
</body>

总结

1. mybatis注解  晚上敲
    单表【重点】
        @Insert
        @Update
        @Delete
        @Select
        @Results
        @Result
    多表【休息日再敲....】
    
2. 综合案例  下午敲
    编程风格(跟帅哥一致...)
    环境搭建
    查询所有
    JDBC
    
    分页查询【晚上敲】
    
    
3. 明天课程非常轻松...
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342