mybatis—动态代理getMapper传入参数输出结果动态sql以及扩展的PageHelper分页
Posted 再来半包
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis—动态代理getMapper传入参数输出结果动态sql以及扩展的PageHelper分页相关的知识,希望对你有一定的参考价值。
mybatis(二)
传统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 语句和 包含的“字符串”替换所在位置。使用Statement把sql语句和{}的内容连接起来,主要用在替换表名,列名,不同列排序等操作。
: 可 以 替 换 表 名 或 者 列 名 , 你 能 确 定 数 据 是 安 全 的 , 可 以 使 用 :可以替换表名或者列名,你能确定数据是安全的,可以使用 :可以替换表名或者列名,你能确定数据是安全的,可以使用
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分页