二、Mybatis的dao层实现原理

一、MyBatis的Dao层实现

1)代理开发方式

以前我们使用dao层,自己要写dao接口和dao实现类,但是Mybatis可以只有接口(类似dao),没有实现;实现实际上是动态代理对象,框架帮我生成
在这里插入图片描述
这个”全限定名还没改↓”
(xml配置的namespace = 接口的全限定名)
在这里插入图片描述
在这里插入图片描述

代码实现:

①配置Mapper
<mapper namespace="com.itheima.dao.UserMapper">	//接口全限定名

<!--查询所有User(无参)-->
    <select id="findAll" resultType="user">
        select * from USER
    </select>
<!--根据id查询User(参数int id)-->
    <select id="findById" parameterType="int" resultType="user">
        select * from user where id = #{id}
    </select>
</mapper>
②定义接口
public interface UserMapper {

    public List<User> findAll() throws IOException;

    public User findById(int id);
}
③测试代码
public class Demo01 {
    public static void main(String[] args) throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        
        //获取动态代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class
        
        //执行SQL
        List<User> userList = mapper.findAll();
        //执行SQL、
        User user = mapper.findById(1);

        System.out.println(userList);System.out.println(user);
        //释放资源
        sqlSession.close();
    }
}

在这里插入图片描述

2)Mybatis映射文件深入:动态SQL

在这里插入图片描述

1)if(重要)

业务场景:用于筛选条件操作数据库,条件不确定

可能1个,可能多个,可能没有
select * from user
select * from user where id=?
select * from user where id=? and username=?
select * from user where id=? and username =? and password=?

Mapper配置文件

<mapper namespace="com.itheima.dao.UserMapper">
    
    <select id="findByConditon" resultType="user" parameterType="user">

        select * from USER
        
        <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>

<where>附加条件</where>
如果附加条件不满足就不进行SQL语句拼接,如果全部满足<where>标签以及标签内等于没有

接口:

    public List<User> findByConditon(User user);

测试:

	@org.junit.Test
 public void Demo02() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

		 //获取动态代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class

        //模拟封装好请求参数的user
        User condition = new User();
        condition.setId(2);
//        condition.setUsername("zhangsan");
//        condition.setPassword("123");
        //执行SQL
        List<User> user = mapper.findByConditon(condition);

        System.out.println(user);

2)foreach

业务场景:循环执行sql的拼接操作

select * from user where id = 1 or id = 2 ,id =3在1-3之内查询: 有什么就查什么,没有就不查询:
等于
select * from user id in(1,2,3)

因此在( )之内,也是不动态的,不确定的。

Mapper配置文件

<mapper namespace="com.itheima.dao.UserMapper">

    <select id="findByIds" parameterType="list" resultType="user">

        select * from user  <!--where id in (1,2,3)-->

        <where>
            <foreach collection="list" open="id in (" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </where>

    </select>

接口:

public List<User> findByIds(List<Integer> ids);//也可以是“数组”,因为( )里面可能有多个id

测试:

    @org.junit.Test
    public void Demo02() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        
        //获取动态代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class

        //模拟封装参数的List集合
        List<Integer> ids = new ArrayList<>();
        ids.add(1);
//        ids.add(2);
//        ids.add(3);
        //执行SQL
        List<User> user = mapper.findByIds(ids);

        System.out.println(user);
        sqlSession.close();

    }

解析:

  • parameterType=“list”:list是框架定义好的别名
  • collection:翻译“集合”,这里填你传入参数的类型,(可以填集合,也可以填数组(数组填“arrays”))
  • open:从哪里开始
  • close:从哪里结束
  • item:翻译“项”,意思是从collection中取出的每一项的值
  • separator:分隔符

select * from user where id in(1,2,3) = select * from user where “open + item + separator + close”

3)抽取重复的sql

抽取:<sql id=“selectUser”>select * from user</sql>
引入:<include refid=“selectUser”></include>

Mapp配置文件
在这里插入图片描述

二、Mybatis核心配置文件深入

1)typeHandlers标签

类型转换器,java数据类型数据库的数据类型,或者 数据库数据类型java数据类型
如果要特将某个java类型能够转数据库数据类型就要自定义,下面是预处理器帮我们转换的。
在这里插入图片描述
在这里插入图片描述
下面使用代码的形式解析:

目的:将java的Date类型 存进 数据库bigint数据类型中;操作数据库时,将返回bigint类型的数据 又转回成 Date类型,返回给java
解决:定义一个类型转换器:将Date类型数据转换成毫秒值的类型存进数据库中;数据库返回时,又将 毫秒值Date


数据库:

在这里插入图片描述

自定义转换器:继承BaseType<T>
③复写4个方法

详解执行SQL对象

public class DateTpyeHandler extends BaseTypeHandler<Date> {//<T>:T为你要转换的数据类型
    //将java类型 转换成 数据库字段的数据类型
    @Override                                                          //int i:为Date参数的位置(执行SQL中传入的参数位置)
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, Date date, JdbcType jdbcType) throws SQLException {
        //将Date转换成毫秒值
        long time = date.getTime();
        //设置参数,设置要转换的毫秒值
        preparedStatement.setLong(i,time);
    }
    
    //将数据库字段数据类型 转换成 java类型
    //String:需要转换数据类型的字段名称
    //ResultSet:数据库查询出来的结果集
    @Override
    public Date getNullableResult(ResultSet resultSet, String s) throws SQLException {
        //获取结果集中需要转换的数据类型(long)
        long aLong = resultSet.getLong(s);
        //转换成Date类型
        Date date = new Date(aLong);
        return date;
    }
    
    //将数据库字段数据类型 转换成 java类型
    //int i:需要转换数据类型的字段位置
    @Override
    public Date getNullableResult(ResultSet resultSet, int i) throws SQLException {
        //获取结果集中需要转换的数据类型(long)
        long aLong = resultSet.getLong(i);
        //转换成Date类型
        Date date = new Date(aLong);
        return date;
    }
    
    //将数据库字段数据类型 转换成 java类型
    //int i:需要转换数据类型的字段位置
    @Override
    public Date getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        //从CallableStatement中获取需要转换的数据类型(long)
        long aLong = callableStatement.getLong(i);
        //转换成Date类型
        Date date = new Date(aLong);
        return date;
    }
}

④MyBatis中注册转换器

注意配置与配置之间的 配置顺序

 <!--注册类型转换器-->
    <typeHandlers>
        <typeHandler handler="com.itheima.handler.DateTpyeHandler"/>
    </typeHandlers>
⑤测试

Mapper配置:

<mapper namespace="com.itheima.dao.UserMapper">

    <sql id="selectUser">select * from user</sql>
    
    <!--插入数据:测试java类型转数据库类型数据-->
    <insert id="save" parameterType="user">
        insert into user values (#{id},#{username},#{password},#{birthday})
    </insert>
    
    <!--查询数据:测试数据库转java类型数据-->
    <select id="findById" parameterType="int" resultType="user">
        select * from user where id = #{id}
    </select>

测试类:

//数据库转java类型数据
    @org.junit.Test
    public void Demo03() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //获取动态代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class

        //执行SQL
        User user = mapper.findById(10);
        System.out.println(user);
        sqlSession.close();

    }
//java转数据库类型数据
    @org.junit.Test
    public void Demo04() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //获取动态代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class

        //模拟封装好请求参数的user
        User user = new User();
        user.setUsername("刘德华");
        user.setPassword("123");
        user.setBirthday(new Date());
        //执行SQL
        mapper.save(user);
        System.out.println(user);
        sqlSession.close();

    }

2)plugins标签

plugins(插件)可以导入插件拓展Mybatis功能,下面 演示分页插件的功能
在这里插入图片描述

①pom.xml:导入分页插件

 <!--分页插件-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>3.7.5</version>
        </dependency>
        <dependency>
            <groupId>com.github.jsqlparser</groupId>
            <artifactId>jsqlparser</artifactId>
            <version>0.9.1</version>
        </dependency>

②Mybatis核心配置文件:配置分页插件

    <!--配置分页插件-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <property name="dialect" value="mysql"/>    <!--指定方言:(指定什么数据库)因为不同数据库sql命令可能不一样-->
        </plugin>
    </plugins>

③测试

    @org.junit.Test
    public void Demo05() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //获取动态代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class
        
        //设置分页相关参数      参数(当前页码,每页显示条数)
        PageHelper.startPage(1,3);//显示第1页的3条数据
        //执行SQL
        List<User> users = mapper.findAll();
        for (User user : users) {
            System.out.println(user);
        }
        sqlSession.close();
    }

分页插件:获取其他相关参数

    @org.junit.Test
    public void Demo05() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //获取动态代理对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);//接口类型.class

        //设置分页相关参数      参数(当前页码,每页显示条数)
        PageHelper.startPage(2,3);//显示第1页的3条数据
        //执行SQL
        List<User> users = mapper.findAll();//查询所有user
        for (User user : users) {
            System.out.println(user);
        }
        //获取分页相关的参数
        PageInfo<User> info = new PageInfo<User>(users);//<T>:你要进行分页的Bean对象    参数:返回查询user的集合
        System.out.println("当前页码:"+info.getPageNum());
        System.out.println("每页显示条数:"+info.getPageNum());
        System.out.println("总条数:"+info.getTotal());
        System.out.println("总页码:"+info.getPages());
        System.out.println("上一页:"+info.getLastPage());
        System.out.println("下一页:"+info.getNextPage());
        System.out.println("第一页:"+info.getFirstPage());
        System.out.println("最后一个:"+info.getLastPage());
        System.out.println("是否为第一页:"+info.isIsFirstPage());
        System.out.println("是否为最一页:"+info.isIsLastPage());
        //....
        sqlSession.close();//释放资源
    }

知识小结

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值