mybatis—动态代理getMapper传入参数输出结果动态sql以及扩展的PageHelper分页

Posted 再来半包

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis—动态代理getMapper传入参数输出结果动态sql以及扩展的PageHelper分页相关的知识,希望对你有一定的参考价值。

传统dao执行数据库方法

public class TestMyBatis {
    @Test
    public void testSelectStduents(){
        StudentDao student=new StudentDaoImpl();
        List<Student> students = student.selectStudents();
        
        students.forEach(student1 -> System.out.println(student1));
    }
    @Test
    public void TestInsertStudent(){
        StudentDao dao=new StudentDaoImpl();
        Student student=new Student();
        student.setId(1004);
        student.setName("ccl");
        student.setEmail("ccl@qq.com");
        student.setAge(20);
        dao.insertStudent(student);
    }
}

List<Student> students = student.selectStudents(); 调用
1、dao对象,类型是StudentDao,全限定名称是:com.hr.qjb.dao.StudentDao

全限定名称,和 namespace是一样的

2、方法名称,selectStudents,这个方法就是mapper文件中的id值, selectStudents

3、通过dao中方法的返回值也可以确定MyBatis要调用的SqlSession的方法

如果返回值是List,调用的是SqlSession.selectList()方法

如果返回值是int , 或是非List的,看mapper文件中的标签是<insert>,<update>就会调用

sqlSession的insert、update等方法

mybatis的动态代理:mybatis根据dao的方法调用,获取执行sql语句的信息

mybatis根据你的dao接口,创建出一个dao接口的实现类,并创建这个类的对象。

完成SqlSession调用方法,访问数据库。

动态代理getMapper

使用SqlSession.getMapper(dao接口.class) 获取这个dao接口的对象

public class TestMyBatis {
    @Test
    public void testSelectStduents(){
        /*
        * 使用mybatis的动态代理机制,使用SqlSession.getMapper(dao接口)
        * getMapper 能获取dao接口对于的实现类对象
        *
        * */
        SqlSession sqlSession= MyBatisUtils.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        //调用dao的方法,执行数据库的操作
        List<Student> students = dao.selectStudents();
        students.forEach(student -> System.out.println(student));
    }

传统dao执行数据库方法,需要接口的实现类支撑,但是使用动态代理以后,可以通过getMapper去代替接口实现类

通过执行System.out.println(dao.getClass().getName());查看dao的类型发现

com.sun.proxy.$Proxy2

可以看到用的就是动态代理

深入理解参数

传入一个简单类型参数

如果想要在进行数据库操作的时候加入参数

传入参数:从Java代码中把数据传入到mapper文件的sql语句中。

1、parameterType:写在mapper文件中的要给属性。表示dao接口中方法的参数的数据类型,

​ 例如StudentDao接口

​ public Student selectStudent ById(Integer id)

parameterType:用来表示dao接口方法参数的数据类型

parameterType它的值是Java的数据类型全限定名称或者是mybatis定义的别名

​ 例如:parameterType=“java.lang.Integer”

​ parameterType=“int”

注意:parameterType不是强制的,mybatis通过反射能够发现接口参数的数类型

​ 所以可以没有。一般我们不写

在mapper文件(dao接口)获取简单类型的一个参数的值,使用#{任意字符}

例如

mapper类

    <select id="selectStudentById" parameterType="java.lang.Integer" resultType="com.hr.qjb.domain.Student">
        select id , name ,email, age from student where id=#{id}
    </select>

测试类

public void testSelectStduents(){
        SqlSession sqlSession= MyBatisUtils.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
    	//传过去参数
        Student student = dao.selectStudentById(1004);
        System.out.println(student);
    }

接口类

public interface StudentDao {
    public Student selectStudentById(Integer id);
}

使用#{}之后,mybatis执行sql是使用jdbc中的PreparedStatement对象

由mybatis执行下面的代码:
1、mybatis创建Connection,PreparedStatement对象

​ String sql=”select id, name ,email,age from student where id=?“

PreparedStatement pst = conn.preparedStatement(sql);

​ pst.setInt(1,1001);

2、执行sql封装为resultType=”com.hr.qjb.domain.Student“这个对象

​ ResultSet rs = ps.executeQuery();

​ Student student = null;

​ while(rs.next()){

​ //从数据库取表的一行数据,存到一个Java对象属性中

​ Student student = new Student();

​ student.setId(rs.getInt(“id”));

​ student.setName(rs.getString(“name”));

​ student.setEmail(rs.getString(“email”));

​ student.setAge(rs.getString(“age”));

}

return student; // 给了dao方法调用的返回值

传入多个参数

使用@Param

当Dao接口方法多个参数,需要通过名称使用参数。在方法形参前面加入@Param(“自定义参数名”),

mapper文件使用#{自定义参数名}

例如定义 List<Student>selectStudent(@Param(“personName”) String name ){ … }

​ mapper 文件 select * from student where name = #{ personName}

接口方法:
List<Student> selectMultiParam(@Param(“personName”) String name ,@Param(“personAge”) int age);

mapper文件:

<select id ="selectMultiParam" resultType="com.hr.qjb.domain.Student">

​ select id , name, email,age from student where name = #{personName} or age = #{personAge}

</select>

实例代码

StudentDao

    //多个参数:命名参数,在形参定义的前面加入@Param("自定义参数名称")
    List<Student> selectMultiParam(@Param("myname") String name ,
                                   @Param("myage") Integer age);

StudentDao.xml

<!--    多个参数,使用@Param命名-->
    <select id="selectMultiParam" resultType="com.hr.qjb.domain.Student">
        select id , name ,email, age from student where name=#{myname} or age=#{myage}
    </select>

测试类

    @Test
    public void testSelectMultiParam(){
        SqlSession sqlSession=MyBatisUtils.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        List<Student> students = dao.selectMultiParam("ccl", 20);
        students.forEach(student -> System.out.println(student));
        sqlSession.close();
    }

使用对象

可以新建一个类,也可以使用已有的类,只要xml文件中#{}花括号中的参数与实体类的属性名对应就可以

studentDao.xml文件中:

多个参数,使用Java对象的属性值,作为参数实际值
使用对象的语法:#{属性名,javaType=类型名称,jdbcType=数据类型} 很少用
JavaType:指Java中的属性数据类型。
jdbcType:在数据库中的数据类型
例如:#{paramName,javaType=java.lang.String,jdbcType=VARCHAR}

<select id="selectMultiObject" resultType="com.hr.qjb.domain.Student">
        select id , name ,email, age from student where
        name=#{paramName,javaType=java.lang.String,jdbcType=VARCHAR}
        or age=#{paramAge,javaType=java.lang.Integer,jdbcType=INTEGER}
    </select>

​ 上面是最为完整的,我们一般用简化的
​ 简化方式:#{属性名} , JavaType,jdbcType的值mybatis反射能获取,不同提供

<select id="selectMultiObject" resultType="com.hr.qjb.domain.Student">
        select id , name ,email, age from student where
        name=#{paramName} or  age=#{paramAge}
    </select>

vo:value object,放一些存储数据的类。比如说 提交请求参数, name, age现在想把name,age 传给一个service类。

vo:view object,从servlet把数据返回给浏览器使用的类,表示显示结果的类。

pojo:普通的有set,get方法的Java类,普通的Java对象

entity(domain域):实体类,和数据库中的表对应的类

使用位置(了解)

使用位置的话是通过接口中方法传递过来的参数从左往右计算,从零开始数,

例如:

List<Student> selectMultiPosition(String name , Integer age);

想要进行查询的话就是

<select id="selectMultiPosition" resultType="com.hr.qjb.domain.Student">
        select id , name ,email, age from student where
        name=#{arg0} or  age=#{arg1}
    </select>

在mybatis 3.4之前 , 使用#{0} ,#{1} 表示

在mybatis3.4之后,使用#{arg0} , #{arg1}

使用map(了解)

List<Student> selectMultiMap(Map<String,Object> map);

使用Map,使用语法#{map的key}

xml

    <select id="selectMultiMap" resultType="com.hr.qjb.domain.Student">
        select id , name , email ,age from student where name=#{name} or age=#{age}
    </select>

测试

    @Test
    public void testSelectMultiMap(){
        //获取SqlSession对象
        SqlSession sqlSession= MyBatisUtils.getSqlSession();
        //通过getMapper方法,得到dao对象
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        //因为要传一个map,所以创建要给map
        Map<String ,Object> map =new HashMap<>();
        map.put("name","ccl");
        map.put("age",20);
        //通过传过去的map调用方法,得到结果集,并且打印
        List<Student> students = dao.selectMultiMap(map);
        students.forEach(student -> System.out.println(student));
    }

占位符

$和#的区别

select id , name ,email, age from student where id=#{id}

#的结果: select id , name ,email, age from student where id=?

select id , name ,email, age from student where id=${id}

$的结果:select id , name ,email, age from student where id=1004

String sql="select id , name ,email, age from student where id = "+“1004”;

使用Statement对象执行sql,效率比PreparedStatement低。

1、#使用?在sql语句中能做站位的,使用PreparedStatement执行sql,效率高

2、#能够避免sql注入,更安全

3、$不使用占位符,是字符串连接方式,使用Statement对象执行sql,效率低

4、$有sql注入的风险,缺乏安全性

5、$:可以替换表名或者列名

#:占位符,告诉mybatis使用实际的参数值代替。并使用PrepareStatement对象执行sql语句。#{…}代替sql语句的"?"。这样做更安全,更迅速,通常也是首选做法,

mappper文件

    <select id="selectStudentById" parameterType="java.lang.Integer" resultType="com.hr.qjb.domain.Student">
        select id , name ,email, age from student where id=#{id}
    </select>

转为MyBatis的执行是:

String sql="select id , name ,email , age from student where id=?";
    PreparedStatement ps= conn.prepareStatement(sql);
ps.setInt(1,1005);

解释:

where id = ? 就是where id = #{id}

ps.setInt(1,1005) , 1005 会替换掉 #{id}

$

$ 字符串替换,告诉mybatis 使用 包 含 的 “ 字 符 串 ” 替 换 所 在 位 置 。 使 用 S t a t e m e n t 把 s q l 语 句 和 包含的“字符串” 替换所在位置。使用 Statement 把sql 语句和 使Statementsql{}的内容连接起来,主要用在替换表名,列名,不同列排序等操作。

: 可 以 替 换 表 名 或 者 列 名 , 你 能 确 定 数 据 是 安 全 的 , 可 以 使 用 :可以替换表名或者列名,你能确定数据是安全的,可以使用 :使

MyBatis输出结果

resultType

resultType:结果类型,指sql语句执行完毕后,数据转为的Java对象。|java 类型是任意的。

resultType结果类型它的值:1、类型的全限定名称, 2、类型的别名, 例如java.lang.Integer别名为int

处理方式:

1、mybatis执行sql语句,然后mybatis调用类的无参数构造方法,创建对象

2、mybatis把ResultSet指定列值赋给同名的属性。

<select id="selectStudentById" parameterType="java.lang.Integer" resultType="com.hr.qjb.domain.Student">
    select id , name ,email, age from student
</select>

对等的jdbc

ResultSet rs =executeQuery(" select id, name ,email ,age from student")

while (rs.next()){

​ Student student =new Student();

​ student.setId(rs.getInt(“id”));

​ student.setname(rs.getString(“name”));

​ student.setEamil(rs.getSring(eamil));

​ student.setInt(rs.getInt(“age”));

}

返回对象类型

<select id="selectStudentReturnViewStudent" resultType="com.hr.qjb.vo.ViewStudent">
    select id ,name  from student where id=#{sid}
</select>

不管查询多少列,他只会存储类中有的属性

返回简单类型

全限定名称

    <select id="countStudent" resultType="java.lang.Integer">
        select count(*) from student
    </select>

或别名

    <select id="countStudent" resultType="int">
        select count(*) from student
    </select>

定义自定义类型的别名

1、在mybatis主配置文件中定义,<typeAlias>定义别名

2、可以在resultType中使用自定义别名

第一种方式:
可以指定一个类型 一个自定义别名
type:自定义类型的全限定名称
alias:别名(短小,容易记忆的)

例如

<typeAlias type="com.hr.qjb.vo.ViewStudent" alias="vstu"/>
<typeAlias type="com.hr.qjb.domain.Student" alias="stu"/>

alias的值就是类的别名

第二种方式
<package> name是包名,这个包中的所有类,类名就是别名(类名不区分大小写)

<package name="com.hr.qjb.domain"/>
<package name="com.hr.qjb.vo"/>

定义路径下的类的类名就是每个类的别名

返回Map

1、列名是map的key,列值是value

2、只能最多返回一行记录,多余一行是错误

<select id="selectMapById" resultType="map">
    select id, name from student where id=#{stuid}
</select>

resultMap

resultMap:结果映射,指定列名和Java对象的属性对应关系。

1、你自定义列值赋给哪个属性

2、当你的列名和属性名不一样时,一定使用resultMap

resultMap使用步骤

xml

使用resultMap
1、先定义resultMap
2、在select标签,使用resultMap来引用定义的

定义resultMap
id:是自定义的名称,表示你定义的这个resultMap
type:Java类型的全限定名称

<resultMap id="studentMap" type="com.hr.qjb.domain.Student">

主键列,使用id标签
column:列名
property:Java类型的属性名

<id column="id" property="id" />

非主键列,使用result

<result column="name" property="email"/>
        <result column="email" property="name"/>
        <result column="age" property="age"/>

如果遇到表中的列名跟类中的属性名不一致时,可以通过resultMap解决, column是表中列名,property是Java类种属性的名字

注意:resultMap和resultType不要一起用,二选一

这是解决列名和属性名不一样的第一种方式

第二种方式

resultType的默认原则是 同名的列值赋值给同名的属性,使用列别名(Java对象的属性名)解决

在sql语句上进行解决

原来:select id , name , email , age from student

为了保持跟Java类中的属性名一样,将sql语句改为

select id as stuid, name as stuname, email as stuemail ,age as stuage from student

解决!

Like模糊查询

第一个模糊查询,在Java代码中 指定like的内容

xml

<select id="selectLikeOne" resultType="com.hr.qjb.domain.Student">
        select id, name , email , age from student  where name like #{name}
    </select>

在测试传值的时候将模糊查询的数据在Java代码中拼接好,传过去

@Test
    public  void  testSelectLikeOne(){
        SqlSession sqlSession=MyBatisUtils.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        //准备好like的内容
        String name ="%磊%";
        List<Student> lists = dao.selectLikeOne(name);
        lists.forEach(student -> System.out.println(student));
    }

第二种方式:在mapper文件中来拼接like内容

xml

<select id="selectLikeTwo" resultType="com.hr.qjb.domain.Student">
        select id , name ,email ,age from student where name like "%" #{name} "%"

    </select>

在mapper文件中写好模糊数据的格式,只需要传一个要查的文字过来

 @Test
    public  void  testSelectLikeTwo(){
        SqlSession sqlSession=MyBatisUtils.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        List<Student> lists = dao.selectLikeTwo("磊");
        lists.forEach(student -> System.out.println(student));
    }

相比之下,第一个方法更加灵活,好理解,如果需要改模糊查询的方法,比如说要李姓:李%。等等再第一种方法里改Java代码的字符串即可,第二个问题要去改动mapper文件

动态sql

动态sql:sql的内容是变化的,可以根据条件获取到不同的sql语句

​ 主要是where部分发生变化。

动态sql的实现,使用的是mybatis提供的标签,<if>,<where>,<foreach>

<if>

1、<if>是判断条件的,

​ 语法<if test="判断Java对象的属性值">

​ 部分sql语句

</if>

<where>

2、<where>用来包含 多个<if>的,当多个if有一个成立的,<where>会自动增加一个where关键字,并去掉if种多余的and,or等

<foreach>

3、<foreach>循环Java中的数组,list集合的。主要用在sql的in语句中。

例如:学生id是 1001、1002、1003的三个学生

sql:select * from student where id in (1001,1002,1003);

语法规则

<foreach collection="" item="" open="" close以上是关于mybatis—动态代理getMapper传入参数输出结果动态sql以及扩展的PageHelper分页的主要内容,如果未能解决你的问题,请参考以下文章

mybatis—动态代理getMapper传入参数输出结果动态sql以及扩展的PageHelper分页

mybatis—动态代理getMapper传入参数输出结果动态sql以及扩展的PageHelper分页

MyBatis源码之getMapper获取代理对象

MyBatis之Mapper动态代理

mybatis 使用session.getMapper

MyBatis 源码分析——动态代理