mybatis进阶3

本文详细介绍了MyBatis的注解开发,包括单表和多表操作,以及在Web环境中的应用。讲解了配置文件、日志设置、连接池的选择,并通过实例展示了如何使用注解实现CRUD操作。同时,文章涵盖了分页查询和一对多、一对一的嵌套查询,以及在实际案例中的应用,如查询所有用户和分页展示。最后,讨论了新增操作的注意事项。
摘要由CSDN通过智能技术生成

mybatis03

内容介绍

  • mybatis的注解开发
    • 掌握单表的操作
    • 理解或者了解多表的操作
  • web案例
    • 查询所有
    • 分页查询

一 配置文件【了解】

properties【了解】

抽取数据库的连接信息

1.将数据库的连接信息放入到一个properties文件中

jdbc.url=jdbc:mysql:///mybatisdb
jdbc.driver=com.mysql.jdbc.Driver
jdbc.username=root
jdbc.password=1234

2.在核心配置文件中通过properties标签导入

    <!--加载src目录下的db.properties文件-->
    <properties resource="db.properties"/>

3.在数据源中就可以通过el表达式的方式去获取数据库连接的4个参数

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

连接池【了解】

mybatis提供了三个方式:

  • POOLED:可以用,使用mybatis内置的连接池 PooledDataSource
  • UNPOOLED:凑合用,使用mybatis内置的连接池 UnPooledDataSource(伪连接池),每次使用连接的时候都使用jdbc的原始操作获取一个连接
  • JNDI:一般不用

等我们学习完spring框架之后,数据源(连接池)交给spring管理了

配置日志【了解】

<setting name="logImpl" value="STDOUT_LOGGING"/>

二 mybatis注解

注解开发是企业的一个趋势,能够简化代码开发.提高开发效率

mybatis学习注解的要求

​ 对于单表CRUD操作,【掌握】

​ 对于多表复杂查询操作,【理解】

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>

1 用户表的CRUD(掌握)

public interface UserDao {
    //@Select("select * from user where id = #{uid}")
    @Select("select id uid,username uname,birthday,sex gender,address addr from user where id = #{uid}")
    @Results(id = "BaseResultMap",value = {
            //主键字段和属性的对应
            @Result(property = "id",column = "uid",id = true),
            //其他字段和属性的对应
            @Result(property = "username",column = "uname"),
            @Result(property = "birthday",column = "birthday"),
            @Result(property = "sex",column = "gender"),
            @Result(property = "address",column = "addr"),
    })
    User findById(int id);

    //@Select("select * from user")
    @Select("select id uid,username uname,birthday,sex gender,address addr from user")
    @ResultMap("BaseResultMap")
    List<User> findAll();

    @Delete("delete from user where id = #{uid}")
    void delete(int id);

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

    @Update("update user set username = #{username},address = #{address} where id = #{id}")
    void update(User user);
}

2 多表嵌套查询(了解)

一对一

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

步骤分析:

  1. 在订单类中添加用户属性
  2. 在UserDao中编写:User findUserByUid(int uid)
    • 在方法上添加注解
  3. 编写OrderDao接口,提供方法: Order findOrderByOidWithUser(int oid);
    • 在方法上添加注解,完成嵌套查询:通过查询结果中uid,调用UserDao.findUserByUid(int uid);

代码实现:

1.在UserDao中添加方法

@Select("select * from user where id = #{uid}")
User findUserByUid(int uid);

2.在OrderDao中添加方法

public interface OrderDao {

    @Select("select * from orders where id = #{oid}")
    //嵌套查询
    @Results(value = {
            @Result(property = "id",column = "id",id = true),
            @Result(property = "orderTime",column = "ordertime"),
            @Result(property = "money",column = "money"),
            @Result(property = "user",column = "uid",javaType = User.class,
                one = @One(select = "com.itheima.dao.UserDao.findUserByUid")
            )
    })
    Order findOrderByOidWithUser(int oid);
}

一对多

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

步骤分析:

  1. 先在用户实体类中提供订单的集合属性
  2. 在OrderDao中编写:List findAllOrdersByUid(int uid);
    • 使用注解配置
  3. 在UserDao中编写一个方法: User findUserByUidWithOrders(int uid);
    • 配置一对多的嵌套查询,通过用户id作为条件,调用OrderDao.findAllOrdersByUid(int uid)

代码实现:

1.在OrderDao中添加的方法

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

2.在UserDao中添加的方法

@Select("select * from user where id = #{uid}")
@Results(value = {
    @Result(property = "id",column = "id",id = true),
    @Result(property = "username",column = "username"),
    @Result(property = "birthday",column = "birthday"),
    @Result(property = "sex",column = "sex"),
    @Result(property = "address",column = "address"),
    @Result(property = "orderList",column = "id",
            many = @Many(select = "com.itheima.dao.OrderDao.findAllOrdersByUid")
           )
})
User findUserByUidWithOrders(int uid);

扩展:懒加载

使用局部懒加载.为了测试方便需要在核心配置文件中配置什么方法都不触发懒加载

扩展:获取新增记录的主键

扩展:动态sql

https://blog.csdn.net/k393393/article/details/94614552

三案例

1 查询所有

需求:在页面上展示所有用户

在项目的首页上有一个超链接,“查询所有用户”,一点此连接就可以将所有的用户数据展示在页面上.

步骤分析

  1. 搭建环境
    • 新建一个web模块(mybatis_case),导入依赖(驱动,mybatis,日志,jstl)
    • 导入日志配置文件
    • 复制mybatis的核心配置文件,复制MybatisUtils,复制User实体类
    • 创建包结构,web,service,dao及其需要的类或者接口

代码实现

  1. 在index.jsp上提供连接

  2. FindAllServlet

    package com.itheima.web.servlet;
    
    import com.itheima.domain.User;
    import com.itheima.service.UserService;
    import com.itheima.service.impl.UserServiceImpl;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.List;
    
    @WebServlet(value = "/findAll")
    public class FindAllServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doGet(request, response);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //1.创建service对象,调用service.findAll方法,接受返回值:list
            UserService userService = new UserServiceImpl();
            List<User> list = userService.findAll();
    
            //2.将list放入request域中
            request.setAttribute("list",list);
    
            //3.请求转发到list.jsp
            request.getRequestDispatcher("/list.jsp").forward(request,response);
        }
    }
    
    
  3. 在UserService中添加findAll方法

    package com.itheima.service.impl;
    
    import com.itheima.dao.UserDao;
    import com.itheima.domain.User;
    import com.itheima.service.UserService;
    import com.itheima.utils.MybatisUtils;
    import org.apache.ibatis.session.SqlSession;
    
    import java.util.List;
    
    public class UserServiceImpl implements UserService {
        @Override
        public List<User> findAll() {
            //1.获取sqlSession对象和UserDao对象
            SqlSession sqlSession = MybatisUtils.openSession();
            UserDao userDao = sqlSession.getMapper(UserDao.class);
    
            //2.调用userDao.findAll(),接受返回值 list
            List<User> list = userDao.findAll();
    
            //3.提交事务和释放资源
            MybatisUtils.commitAndClose(sqlSession);
    
            //4.返回list
            return list;
        }
    }
    
    
  4. 在UserDao中添加findAll方法,提供对应的映射文件

    package com.itheima.dao;
    
    import com.itheima.domain.User;
    
    import java.util.List;
    
    public interface UserDao {
        List<User> findAll();
    }
    
    
    <?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.itheima.dao.UserDao">
        <select id="findAll" resultType="user">
            select * from user
        </select>
    </mapper>
    
  5. 创建list.jsp

2 分页查询

需求:以分页的形式在页面上展示所有用户

分析:

分页的分类:

  1. 物理分页:每次去数据库中只查询当前页的数据,保证数据的及时性.
  2. 逻辑分页:一次性将所有的数据查询出来,放入内存中,若需要某页数据的话再从内存去读取即可.

mysql中实现物理分页需要使用:limit

limit m,n;

m:开始的索引

n:向后查询的记录数


m的规律:

若要做分页查询:servlet需要获取俩数据:查询页码和每页显示的条数


页面上需要展示的数据:

  • 当前页的数据集合 limit m,n
  • 总记录数
  • 总页数
  • 当前页
  • 每页显示的条数

为了方便在各层之间进行数据的传递,一般会把上面的5个基本信息封装成一个实体类,例如:PageBean

pageBean中的字段和方法

  • List dataList;//当前页的数据集合 limit m,n
  • int totalCount;//总记录数
  • int totalPage;//总页数
  • int pageNumber;//当前页
  • int pageSize;//每页显示的条数

方法:

  • 重写getTotalPage的方法
    • 总记录数和每页显示的条数进行计算
  • 提供一个getStartIndex的方法(开始索引)
    • return (pageNumber-1)*pageSize;
  • 提供一个带有页码和每页显示的条数的构造器

PageBean

public class PageBean<T> {
    private List<T> dataList;//当前页的数据集合 limit m,n
    private int totalCount;//总记录数
    //int totalPage;//总页数
    private int pageNumber;//当前页
    private int pageSize;//每页显示的条数

    public PageBean(int pageNumber, int pageSize) {
        this.pageNumber = pageNumber;
        this.pageSize = pageSize;
    }

    //重写获取总页数的方法
    public int getTotalPage() {
        //可以使用三元运算符 或者 if判断
        return (int)Math.ceil(totalCount*1.0/pageSize);
    }

    //获取开始索引的方法
    public int getStartIndex(){
        return (pageNumber - 1)*pageSize;
    }

    public List<T> getDataList() {
        return dataList;
    }

    public void setDataList(List<T> dataList) {
        this.dataList = dataList;
    }

    public int getTotalCount() {
        return totalCount;
    }

    public void setTotalCount(int totalCount) {
        this.totalCount = totalCount;
    }



    /*public void setTotalPage(int totalPage) {
        this.totalPage = totalPage;
    }*/

    public int getPageNumber() {
        return pageNumber;
    }

    public void setPageNumber(int pageNumber) {
        this.pageNumber = pageNumber;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }
}

步骤分析:

代码实现:

  1. 修改index.jsp

  2. FindByPageServlet

    package com.itheima.web.servlet;
    
    import com.itheima.domain.User;
    import com.itheima.service.UserService;
    import com.itheima.service.impl.UserServiceImpl;
    import com.itheima.utils.PageBean;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    @WebServlet(value = "/findByPage")
    public class FindByPageServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doGet(request, response);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //1.设置默认页和默认的条数
            int pageNumber = 1;
            int pageSize = 5;
    
            //2.获取页面上传递过来的页码
            String pageNumberStr = request.getParameter("pageNumber");
    
            //3.若有页码的话,就需要修改要查询的页码
            try {
                pageNumber = Integer.parseInt(pageNumberStr);
            } catch (NumberFormatException e) {
            }
    
            //4.创建UserService对象,调用方法,查询当前页的所需要的数据,返回值:PageBean
            UserService userService = new UserServiceImpl();
            PageBean<User> pageBean = userService.findByPage(pageNumber,pageSize);
    
            //5.将pageBean放入request域中
            request.setAttribute("pb",pageBean);
    
            //6.请求转发到list_page.jsp
            request.getRequestDispatcher("/list_page.jsp").forward(request,response);
        }
    }
    
    
  3. 在UserService中添加findByPage方法

        @Override
        //查询指定页上的所有数据
        public PageBean<User> findByPage(int pageNumber, int pageSize) {
            //1.创建pageBean对象
            PageBean<User> pb = new PageBean<>(pageNumber,pageSize);
    
            //2.获取sqlSession和UserDao对象
            SqlSession sqlSession = MybatisUtils.openSession();
            UserDao userDao = sqlSession.getMapper(UserDao.class);
    
            //3.调用dao的方法,查询总记录数
            int totalCount = userDao.findTotalCount();
    
            //4.调用dao的方法,查询当前页的数据集合
            List<User> dataList = userDao.findByPage(pb.getStartIndex(),pb.getPageSize());
    
            //5.别忘记释放资源
            MybatisUtils.commitAndClose(sqlSession);
    
            //6.将总记录数和当前页的数据集合封装到pageBean中
            pb.setTotalCount(totalCount);
            pb.setDataList(dataList);
    
            //7.返回pagebean
            return pb;
        }
    
  4. 在UserDao中添加俩方法及其映射文件

    int findTotalCount();
    
    List<User> findByPage(@Param("startIndex") int startIndex,@Param("pageSize") int pageSize);
    
        <select id="findTotalCount" resultType="int">
            select count(*) from user
        </select>
    
        <select id="findByPage" resultType="user">
            select * from user limit #{startIndex},#{pageSize}
        </select>
    
  5. 复制list.jsp,重命名为list_page.jsp


list.jsp编写步骤

  1. 先展示当前页的数据集合 遍历pb.dataList
  2. 处理分页条
    • 先展示第几页 共几页
    • 处理首页和上一页
    • 再处理尾页和下一页
    • 处理所有页码,使用普通for循环 从1展示到总页数
      • 若是当前页的话,不加超链接,加上一个class=“active”

3 前五后四

image-20210516161305783
//修改pagebean代码
	private int start;
    private int end;

    public int getStart() {
        calcStartAndEnd();
        return start;
    }
    public void setStart(int start) {
        this.start = start;
    }
    public int getEnd() {
        return end;
    }
    public void setEnd(int end) {
        this.end = end;
    }

    //计算开始页和结束页
    private void calcStartAndEnd(){
        //1.判断总页数<=10
        if (getTotalPage()<=10) {
            start = 1;
            end = getTotalPage();
        }else {
            start = pageNumber - 5;
            end = pageNumber + 4;

            //2.处理溢出
            if (start < 1) {
                start = 1;
                end = 10;
            }

            if(end > getTotalPage()){
                start = getTotalPage() - 9;
                end = getTotalPage();
            }
        }
    }

4 扩展:新增操作注意事项

在servlet中封装数据的时候,若使用BeanUtils封装会出现问题,原因是:BeanUtils不能将传过来的生日字符串转换成日期类型.解决方案如下:

  • 方案1:不使用BeanUtils封装
  • 方案2:自定义字符串转日期的转换器

以下为自定义转换器的编写和使用步骤

  1. 自定义类,实现org.apache.commons.beanutils.Converter接口,重写convert方法

    public Object convert(Class aClass, Object o) {
            //1.将参数o强转为字符串
        	
        	//2.将字符串转换成日期对象返回
            return null;
    }
    
  2. 在调用BeanUtils封装数据之前,先注册自定义类型转换器:ConvertUtils.register(类型转换器对象, Date.class);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值