MyBatis详解(二)Dao的代理

第三章 MyBatis的Dao的代理

3.1 dao代理

1.mybatis提供代理:

mybatis创建Dao接口的实现类对象,完成对sql语句的执行。mybatis创建一个对象代替你的dao实现类功能。

2.使用mybatis代理的要求:

​ 1)mapper文件中的namespace一定dao接口的全限定名称。

​ 2)mapper文件中标签的id是dao接口方法名称。

3.mybatis代理的实现方式

​ 使用SqlSession对象的方法getMapper(dao.class)

​ 例如:现在有StudentDao接口。

SqlSession session = MyBatisUtils.getSqlSession();
StudentDao dao = session.getMapper(StudentDao.class);
Student student = dao.selectById(1001);

//上面代码中
StudentDao dao = session.getMapper(StudentDao.class);
//等同于
StudentDao dao = new StudentDaoImpl();
public class MyTest {

    @Test
    public void testSelectById(){
//        1.获取SqlSession
        SqlSession session= MyBatisUtil.getSqlSession();
//        2.获取dao的代理
        StudentDao dao = session.getMapper(StudentDao.class);
        Student student = dao.selectById(1005);
        System.out.println("student = "+ student);
//        3.关闭SqlSession对象
        session.close();
    }

    @Test
    public void testSelectStudents(){
        SqlSession session = MyBatisUtil.getSqlSession();
        StudentDao dao = session.getMapper(StudentDao.class);
        System.out.println("dao==="+dao.getClass());
//        dao===class com.sun.proxy.$Proxy2 代理类型。代替了实现类的功能。
        List<Student> students = dao.selectStudents();
        students.forEach(stu-> System.out.println("stu="+stu));
        session.close();
    }

}

3.2理解参数

理解参数是:通过Java程序把数据传入到mapper文件中的sql语句。参数主要是指dao接口方法的形参。

1.parameterType

​ parameterType:表示参数的类型,指定dao方法的形参数据类型。这个形参的数据类型是给mybatis使用。mybatis在给sql语句的参数赋值时使用。PreparedStatement.setXXX(位置,值)

    parameterType="java.lang.Integer
    parameterType="int"
    parameterType="integer"

    第一个用法:java类型的全限定类型名称 parameterType="java.lang.Integer
    第二个用法:mybatis定义的Java类型的别名
    
    parameterType: mybatis通过反射机制可以获得 dao接口方法参数的类型,可以不写。

例子

<?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.sunny.dao.StudentDao">
    <!-- 使用insert,update,delete,select标签写sql语句-->
<!--
    parameterType:指定接口形参的类型
                  这个属性的值可以使用 java类型的全限定名称或者 mybatis定义的别名。

    mybatis执行的sql语句:select id,name,email,age from student where id=?
    ? 是占位符,使用jdbc中的PreparedStatement执行这样的sql语句

    PreparedStatement pst = conn.preparedStatement("select  id,name,email,age from student where id=?");

    给?的位置赋值
    参数Integer,pst.setInt(1,1005);
    参数是String,执行pst.setString(1,"1005");
    parameterType="java.lang.Integer
    parameterType="int"
    parameterType="integer"

    第一个用法:java类型的全限定类型名称 parameterType="java.lang.Integer
    第二个用法:mybatis定义的Java类型的别名

    parameterType: mybatis通过反射机制可以获得 dao接口方法参数的类型,可以不写。
-->
    <select id="selectById" parameterType="integer"resultType="com.sunny.domain.Student">
        select  id,name,email,age from student where id=#{studentId}
    </select>


</mapper>

2.dao接口方法是一个简单类型的参数

//    dao接口的方法形参是一个简单类型的
//    简单类型:java基本数据类型和String
    Student selectByEmail(String email);
<!--
    dao接口是一个简单类型的参数
    mapper文件,获取这个参数值,使用#{任意字符}
-->
    <select id="selectByEmail" resultType="com.sunny.domain.Student">
        select id,name,email,age from student where email=#{studentEmail}
    </select>

3.dao接口方法有多个简单类型的参数 (推荐使用!!!)

这种方式可读性更高。

@Param:命名参数,在方法的形参前面使用的,定义参数名。这个名称可以用在mapper文件中。

​ dao接口,方法的定义

 /*
    * 多个简单类型的参数
    * 使用@Param命名参数,注解是mybatis提供的
    * 位置:在形参定义的前面
    * 属性:value自定义的参数名称
    * */
    List<Student> selectByNameOrAge(@Param("myname") String name, @Param("myage") Integer age);

mapper文件

<!--
    多个简单类型的参数,
    当使用了@Param命名后,例如@Param("myname"),
    在mapper中,使用#{命名的参数},例如#{myname}
-->
    <select id="selectByNameOrAge" resultType="com.sunny.domain.Student">
        select id,name,email,age from student where name=#{myname} or age=#{myage}
    </select>

4.dao接口方法使用对象作为参数(多个参数)

​ 方法的形参是一个java对象。这个Java对象表示多个参数。使用对象的属性值作为参数使用。

​ dao接口

   /*
    * 一个java对象作为参数(对象有属性,每个属性有set,get方法)
    * */

    List<Student> selectByObject(Student student);
    /*
    * 这种方法在开发中常用,可以用过一个对象传递多个属性值。作为多个条件使用
    * */
    List<Student> selectByQueryParam(QueryParam param);

mapper文件

<!--
    一个Java对象作为方法的参数,使用对象的属性作为参数值使用
    简单的语法: #{属性名},mybatis调用此属性的getXXX()方法获取属性
-->
    <select id="selectByObject" resultType="com.sunny.domain.Student">
        select id,name,email,age from student where name =#{name} or age=#{age}
    </select>
    <select id="selectByQueryParam" resultType="com.sunny.domain.Student">
        select id,name,email,age from student where name =#{p1} or age=#{p2}
    </select>

工具对象

public class Student {
    private Integer id;
    private String name;
    private String email;
    private Integer age;
    //get和set方法
}
package com.sunny.vo;

public class QueryParam {
    private Object p1;
    private  Object p2;
	//get 和set方法。
}

​ 复杂的方式,就是把参数对用的java数据类型和SQL的数据类型以代码方式写名(没有要求不必要的)

    <select id="selectByObject" resultType="com.bjpowernode.domain.Student">
        select id,name,email,age from student where
        name=#{name,javaType=java.lang.String,jdbcType=VARCHAR}
        or
        age=#{age,javaType=java.lang.Integer,jdbcType=INTEGER}
    </select>
4.1更新操作

​ xml文件

<!--    更新-->
    <update id="updateStudent">
        update student set name=#{name},email=#{email} where id = #{id}
    </update>

​ Dao接口

    /*
    * 更新
    * */
    int updateStudent(Student student);

​ 测试类

    @Test
    public void testUpdateStudent(){
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);

        Student student = new Student();
        student.setId(1003);
        student.setName("张峰");
        student.setEmail("ZHANGFENG@qq.com");
        student.setAge(20);

        int rows = dao.updateStudent(student);
        sqlSession.commit();
        System.out.println("更新学生的rows="+rows);

        sqlSession.close();

    }

5.dao接口中多个简单类型的参数,使用位置(了解)

参数位置:dao接口中方法的形参列表,从左往右,参数的位置是 0,1,2…

语法格式:#{arg0},#{arg1}

<!--
    selectByPosition  mybatis版本是 3.5.1
    使用位置获取参数,dao接口方法是多个简单类型的参数
    语法:#{arg0},#{arg1}....

    以下面的一个为例如果把where name=#{arg1} or age =#{arg0}  (String name,Integer age);
    那么查询是传参的顺序是  (Integer age,String name);这种方法可能无法了解到位置信息
-->
    <select id="selectByPosition" resultType="com.sunny.domain.Student">
        select id,name,email,age from student where name=#{arg0} or age =#{arg1}
    </select>
   /*
    * 使用位置,获取参数
    * */
    List<Student> selectByPosition(String name,Integer age);

6.dao接口方法使用Map作为参数

​ 所有java规范中Map作为参数都不建议!!!

​ 不够清晰,可读性比较差。好处是可以添加很多数据。

​ map作为dao接口的参数,使用key获取参数值,mapper文件中,语法格式#{key}

      /*
    * 使用Map作为参数
    * */
    List<Student> selectStudentByMap(Map<String,Object> map);  



	@Test
    public void testSelectByMap(){
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);

//      按位置传递参数
        Map<String,Object> map = new HashMap<>();
        map.put("myname","李思思");
        map.put("myage","20");
        List<Student>students = dao.selectStudentByMap(map);

        students.forEach(stu -> System.out.println("stu="+stu));

        sqlSession.close();

    }

    <!--
        使用Map传递参数,
        在mapper文件中,获取map的值,是通过key获取的,语法:#{key}
        selectStudentByMap
    -->
    <select id="selectStudentByMap" resultType="com.sunny.domain.Student">
        select id,name,email,age from student where name=#{myname} or age=#{myage}
    </select>

3.3 #和$的区别

1. # 占位符

语法:#{字符}

​ mybatis处理#{}使用jdbc对象是PrepareStatment对象。

    <select id="selectById" parameterType="integer"
            resultType="com.sunny.domain.Student">
        select  id,name,email,age from student where id=#{studentId}
    </select>
mybatis创建PrepareStatement对象,执行sql语句。
String sql = "select id name,email,age from student where id=?";
PrepareStatement pst = conn.prepareStatement(sql);
//传递参数
pst.setInt(1,1001);
//执行sql语句
ResultSet rs = pst.executeQuery();

#{}特点

1)使用的PrepareStatement对象,执行sql语句,效率高。

2)使用的PrepareStatement对象,能避免sql语句,sql语句执行更安全。

3)#{}常常作为列值使用的,位于等号的右侧,#{}位置的值和数据类型有关。

2.占位符

语法:${字符}

mybatis执行${}占位符的sql语句

    <select id="selectById" parameterType="integer"
            resultType="com.sunny.domain.Student">
        select  id,name,email,age from student where id=${studentId}
    </select>
${} 表示字符串连接,把sql语句的其他内容和${}内容使用 连接的方式连在一起。
String sql = "select  id,name,email,age from student where id="+"1001";

//相当于mybatis创建Statement对象,执行sql语句。
Statement stmt = conn.createStatement(sql);
ResultSet rs = stmt.execuQuery();

${}的特点

1)使用Statement对象,执行sql语句,效率低。

2)${}占位符的值,使用字符串连接方式,有sql注入的风险。有代码安全问题。

3)${}数据是原样使用的,不会区分数据类型。

4)** 常 用 作 表 名 或 者 列 名 ∗ ∗ , 在 能 保 证 数 据 安 全 的 情 况 下 使 用 {}常用作表名或者列名**,在能保证数据安全的情况下使用 使{}

寻找李四 并按列名id排序
    <select id="queryStudentOderByColName" resultType="com.sunny.domain.Student">
        select * from ${tableName} where  name =#{myname} order by ${colName} desc
    </select>
dao接口
    List<Student> queryStudentOderByColName(@Param("myname")String name,
                                            @Param("colName") String colName,
                                            @Param("tableName") String tableName);
测试类
    @Test
    public void testQueryStudentOrderByColName(){
//        1.获取SqlSession
        SqlSession session= MyBatisUtil.getSqlSession();
//        2.获取dao的代理
        StudentDao dao = session.getMapper(StudentDao.class);

        List<Student> students = dao.queryStudentOderByColName("李四","id","student");

        students.forEach(stu-> System.out.println("stu="+stu));
        session.close();
    }

4 封装MyBatis输出结果(开发中用对象比较多)

封装输出结果:MyBatis执行sql语句,得到ResultSet,转为java对象。

resultType,resultMap

4.1 resultType

​ resultType属性:在执行select时使用,作为标签的属性出现。

​ resultType:表示结果类型,mysql执行sql语句。得到java对象的类型。他的值有两种。

​ 1)java类型的全限定名称。2)使用别名。

1)resultType:表示java自定义对象。
    <select id="selectById" parameterType="integer"
            resultType="com.sunny.domain.Student">
        select  id,name,email,age from student where id=#{studentId}
    </select>
Student selectById(Integer id);
resultType:现在使用java类型的全限定名称。表示的意思mybatis执行sql,把ResultSet的数据转为Student类型的对象。mybatis会做以下操作:
1.调用com.sunny.domain.Student的无参构造方法,创建对象。
    Student student = new Student();//使用反射创建对象。
2.同名的列赋值给同名的属性。
    student.setId(rs.getInt("id"));
    student.setName(rs.getString("name"));
3.得到java对象,如果dao接口返回值是List集合,mybatis把student对象放入到List集合。
    所以执行
    Student mystudent = dao.selectById(1001);
	得到数据库中id=1001这行数据,这行数据的列值,赋值给mystudent对象的属性。能得到mystudent对象就相当于id=1001这行数据。

​ PS:属性中同名属性对应同名列,命名保持一致!!

2)resultType表示简单类型。

dao方法

    long countStudent();

mapper文件

<!--    
    执行sql语句,得到是一个值(一行一列)
-->
    <select id="countStudent" resultType="java.lang.Long">
        select count(*) from student
    </select>

3)resultType:表示一个map结构
DAO接口
    
//    查询结果返回一个Map
    Map<Object,Object> selectMap(@Param("stuid") Integer id);

Test测试类
    
    @Test
    public void testSelectMap(){
//        1.获取SqlSession
        SqlSession session= MyBatisUtil.getSqlSession();
//        2.获取dao的代理
        StudentDao dao = session.getMapper(StudentDao.class);

        Map<Object,Object> map = dao.selectMap(1006);
        System.out.println("map===="+map);
//        3.关闭SqlSession对象
        session.close();

        System.out.println("name==="+map.get("name"));
        System.out.println("id  ==="+map.get("id"));
        System.out.println("email ==="+map.get("email"));
    }

mapper文件

<!--
    执行sql得到一个Map结构数据,mybatis执行sql,把ResultSet转为map
    sql执行结果,列名作为value
    sql执行得到是一行记录,转为map结构是正确的。

   dao接口返回的是一个map,sql语句最多能获得一行记录,多出一行是错误的。
-->
    <select id="selectMap" resultType="java.util.HashMap">
        select id,name,email from student where id=#{stuid};
    </select>
练习题

​ 输入一个省份id,得到省份id,省份name,城市名称

例如输入 省份id = 1

1 河北 1石家庄 2秦皇岛

先写sql

## 给列起别名
SELECT p.id,p.name,c.id,c.name FROM province p JOIN city c ON p.id = provinceid WHERE p.id = 1;
DAO
public interface ProvinceDao {
    List<ProvinceCity> selectProvinceCityList(Integer provinceId);
}

ProvinceDao.xml

<mapper namespace="com.bjpowernode.dao.ProvinceDao">
    <!-- 使用insert,update,delete,select标签写sql语句-->

<!--    对于新增加的mapper文件需要在主文件声明-->
    <select id="selectProvinceCityList" resultType="com.bjpowernode.vo.ProvinceCity">
        SELECT p.id,p.name,c.id,c.name FROM province p JOIN city c ON p.id = provinceid WHERE p.id = #{pid};
    </select>

</mapper>

resourse下的mybatis.xml文件

        <mapper resource="com/bjpowernode/dao/ProvinceDao.xml"/>

    </mappers>
    @Test
    public void testSelectProvinceCity(){
//        1.获取SqlSession
        SqlSession session= MyBatisUtil.getSqlSession();
//        2.获取dao的代理
        ProvinceDao dao = session.getMapper(ProvinceDao.class);

        List<ProvinceCity> list = dao.selectProvinceCityList(1);

        session.close();

        list.forEach(p -> System.out.println(p));
    }

4.2 resultMap

resultMap:结果映射。自定义列名和java对象属性的对应关系。常在列名和属性名不同的情况。

用法:

​ 1.先定义resultMap标签,指定上面定义的resultMap的id值。

​ 2.在select标签使用resultMap属性,指定上面定义的resultMap的id值

<!--    使用resultMap定义列和属性的关系-->
<!--    定义resultMap
        id:给resultMap的映射关系起个名称,唯一值。
        type:java类型的全限定名称
-->

    <resultMap id="customMap" type="com.bjpowernode.vo.CustomObject">
<!--        定义属性列名和属性名的对应-->
<!--        主键列使用id标签-->
        <id column="id" property="cid"/>
<!--        非主键列类型使用result标签-->
        <result column="name" property="cname"/>
<!--        列名和属性名相同不要定义-->
        <result column="email" property="email"/>
        <result column="age" property="age"/>

    </resultMap>

<!--    使用resultMap属性,指定映射关系的id
        resultType和resultMap不能同时使用,二选一
-->
    <select id="selectById2" resultMap="customMap">
        select id,name,email,age from student where id=#{stuid};
    </select>
CustomObject selectById2(@Param("stuid") Integer id);
java.lang.ExceptionInInitializerError
配置文件出错,同一个id  <select id="selectById2" 使用了两次。

5.自定义别名(不推荐使用)

​ mybatis提供的对java类型定义简短,好记的名称。(推荐使用全限定名称

自定义别名的步骤:

1)在mybatis主配置文件,使用typeAliase标签声明别名。

2)在mapper文件中,resultType=“别名”

声明别名(mybatis主配置文件)

    </settings>
<!--    声明别名-->
    <typeAliases>
<!--        第一种语法格式
            type:java类型的全限定名称(自定义类型)
            alias:自定义别名

			优点:别名可以自定义
            缺点:每个类型单独定义
-->
        <typeAlias type="com.sunny.domain.Student" alias="stu"></typeAlias>
    </typeAliases>
    <environments default="development">
        
mapper文件
resultType="别名"
	<select id="selectById" parameterType="integer"
            resultType="stu">
        select  id,name,email,age from student where id=#{studentId}
    </select>

第二种方式

<!--        
            第二种方式
                name:包名,mybatis会把这个包所有类名作为别名(不用区分大小写)
                
                优点:使用方便,一次给多个类定义别名
                缺点:别名不能自定义,必须是类名。
-->
        <package name="com.sunny.domain"/>
        <package name="com.sunny.vo"/>
    </typeAliases>

PS: 推荐使用全限定名称

6.列名和Java对象属性名称不一样解决方式

PS:实际开发中列名和属性名通常不一样 sql命名规范和java命名规范不一样。

1)使用resultMap:自定义列名和属性名称对应关系。

2)使用resultType:使用列别名,让别名和Java对象属性名称一样

<!--    使用列别名解决列名和属性名不同的问题-->
    <select id="selectById3" resultType="com.bjpowernode.vo.CustomObject">
        select id as cid,name as cname,email,age from student where id = #{stuid}
    </select>

7.like

第一种方式:在java程序中,把like内容组装好。把这个内容传入到sql语句(灵活)
select id ,name ,email,age from student where name like "%李%"

接口

//    like第一种方式
    List<Student> selectLikeOne(@Param("name") String name);

Mapper

<!--    like第一种方式-->
    <select id="selectLikeOne" resultType="com.bjpowernode.domain.Student">
        select * from student where name like #{name}
    </select>

测试

    @Test
    public void testLikeOne(){
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);

        String name = "%李%";//"李%" “%李”
        List<Student> students = dao.selectLikeOne(name);

        sqlSession.close();

        students.forEach(stu -> System.out.println(stu));
    }
第二种方式:在sql语句,组织like的内容。(不灵活方便)

sql语句like的格式:where name like “%“空格#{name}空格”%”

    //like第二种方式
    List<Student> selectLikeTwo(@Param("name") String name);
    <!--    like第二种方式-->
    <select id="selectLikeTwo" resultType="com.bjpowernode.domain.Student">
        select * from student where name like "%" #{name} "%"
    </select>
    @Test
    public void testLikeTwo(){
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);

        String name = "李";
        List<Student> students = dao.selectLikeTwo(name);

        sqlSession.close();

        students.forEach(stu -> System.out.println(stu));
    }

();

    students.forEach(stu -> System.out.println(stu));
}

#### 第二种方式:在sql语句,组织like的内容。(不灵活方便)

sql语句like的格式:where name like "%"空格#{name}空格"%"

```java
    //like第二种方式
    List<Student> selectLikeTwo(@Param("name") String name);
    <!--    like第二种方式-->
    <select id="selectLikeTwo" resultType="com.bjpowernode.domain.Student">
        select * from student where name like "%" #{name} "%"
    </select>
    @Test
    public void testLikeTwo(){
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);

        String name = "李";
        List<Student> students = dao.selectLikeTwo(name);

        sqlSession.close();

        students.forEach(stu -> System.out.println(stu));
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值