开始时间:2021-12-06
课程链接:动力节点MyBatis
传统dao的实现
过程和之前一样,可以选择复制
因为每次写StudentDao都差不多,所以我们可以设置一个模板来实现快捷生成
File-Setting-File and Code Templates
新建一个未命名的 unnamed模板,自己命名,将要重复使用的部分复制进去,后缀名改为xml
同理resources下的mybatis.xml也可以这样生成(先设置好该模板)
我们之前的测试,是没怎么用上StudentDao这个接口的
现在其他大部分代码不变,设置一个该接口的实现类
package BUPT.dao.implement;
import BUPT.dao.StudentDao;
import BUPT.entity.Student;
import BUPT.util.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import java.util.List;
public class StudentDaoImp implements StudentDao {
@Override
public List<Student> selectStudents() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
String sqlId = "BUPT.dao.StudentDao.selectStudents";
List<Student> students = sqlSession.selectList(sqlId);
sqlSession.close();
return students;
}
@Override
public int insertStudent(Student student) {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
String sqlId = "BUPT.dao.StudentDao.insertStudent";
sqlSession.commit();
int num = sqlSession.insert(sqlId, student);
sqlSession.close();
return num;
}
}
再写一个测试类
package BUPT;
import static org.junit.Assert.assertTrue;
import BUPT.dao.StudentDao;
import BUPT.dao.implement.StudentDaoImp;
import BUPT.entity.Student;
import org.junit.Test;
import java.util.List;
/**
* Unit test for simple App.
*/
public class AppTest {
@Test
public void testSelectStudents() {
StudentDao dao = new StudentDaoImp();
List<Student> students = dao.selectStudents();
for (Student student : students) {
System.out.println(student);
}
}
@Test
public void testInsertStudent() {
StudentDao dao = new StudentDaoImp();
Student student = new Student();
student.setAge(30);
student.setEmail("yaoming@qq.com");
student.setId(1007);
student.setName("yaoming");
int num = dao.insertStudent(student);
System.out.println("添加对象个数为" + num);
}
}
这样才算把这个接口用上。
但是还是有不足的地方
测试类代码依然有不少重复,解决办法就是使用动态代理
动态代理的实现
在上面的例子中,实现方法主要是以下代码
单独写了一个implement类
public List<Student> selectStudents() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
String sqlId = "BUPT.dao.StudentDao.selectStudents";
List<Student> students = sqlSession.selectList(sqlId);
sqlSession.close();
return students;
}
然后测试类对应的写
public void testSelectStudents() {
StudentDao dao = new StudentDaoImp();
List<Student> students = dao.selectStudents();
for (Student student : students) {
System.out.println(student);
}
}
当我的方法变多了以后,就得在StudentDaoImp类里面继续去实现StudentDao类新的方法
并且在测试类中,新建StudentDaoImp类
我们考虑使用动态代理对其进行简化
参考博客
动态代理的好处
动态代理: 在程序执行过程中,使用jdk的反射机制,创建代理类对象, 并动态的指定要代理目标类。
换句话说: 动态代理是一种创建java对象的能力,不用创建TaoBao类,就能创建代理类对象。
动态:在程序执行时,调用jdk提供的方法才能创建代理类的对象。
也就是说,我们不需要写StudentDaoImp类,利用动态代理实现其效果的替代
删除StudentDaoImp类
改写测试类的代码为
getMapper(dao接口)实现对象的创建,这个对象就能执行dao对象的所有方法
mapper根据命名空间自己去寻找对应的方法
<mapper namespace="BUPT.dao.StudentDao">
public void testSelectStudents(){
/**
* 使用mybatis的动态代理机制, 使用SqlSession.getMapper(dao接口)
* 参数是接口的class
* getMapper能获取dao接口对于的实现类对象。
*/
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
//com.sun.proxy.$Proxy2 : jdk的动态代理
System.out.println("dao="+dao.getClass().getName());
//调用dao的方法, 执行数据库的操作
List<Student> students = dao.selectStudents();
for(Student stu: students){
System.out.println("学生="+stu);
}
}
同理写出插入的方法
@test
public void testInsertStudent(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
Student student = new Student();
student.setId(1008);
student.setName("李飞");
student.setEmail("dunshan@qq.com");
student.setAge(28);
int nums = dao.insertStudent(student);
sqlSession.commit();
System.out.println("添加对象的数量:"+nums);
}
值得一提的是,pom.xml文件中的内容,一定要和module名.xml文件的内容一致,版本要一样
通过我们的接口名和方法名,映射到对应xml文件中的sql语句,知道了sql语句就知道了返回值类型
传参
当然也可以写
<select id="selectStudentById" parameterType="java.lang.Integer" resultType="BUPT.entity.Student">
通过parameterType来决定,但不是强制要写的。
注意:简单类型的传参,使用#{待传参参数名}
多个参数传参(比如SQL语句涉及多个字段的查询),使用@param注解命名参数
StudentDao
public interface StudentDao {
public Student selectStudentById(Integer id);
public Student selectStudentByTwoParams(@Param("myid") Integer id, @Param("myage") Integer age);
}
StudentDao.xml
<select id="selectStudentByTwoParams" resultType="BUPT.entity.Student">
select id, name, email, age
from student
where id = #{myid} and age=#{myage}
</select>
Test
public void testSelectStudentByTwoParams() {
/**
* 使用mybatis的动态代理机制, 使用SqlSession.getMapper(dao接口)
* 参数是接口的class
* getMapper能获取dao接口对于的实现类对象。
*/
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
//com.sun.proxy.$Proxy2 : jdk的动态代理
System.out.println("dao=" + dao.getClass().getName());
//调用dao的方法, 执行数据库的操作
//传入的1002是整型值。由我们写的StudentDao.xml文件写的parameterType决定,但不是强制要写的
//<select id="selectStudentById" parameterType="java.lang.Integer" resultType="BUPT.entity.Student">
Student student = dao.selectStudentByTwoParams(1002, 18);
System.out.println(student);
}
使用对象传参
也就是上面插入新对象时的方法
StudentDao
public interface StudentDao {
int insertStudent(Student student);
}
StudentDao.xml
<insert id="insertStudent">
<!--起到占位符的作用-->
insert into student values(#{id},#{name},#{email},#{age})
</insert>
测试类
public void testInsertStudent(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
Student student = new Student();
student.setId(1008);
student.setName("李飞");
student.setEmail("dunshan@qq.com");
student.setAge(28);
int nums = dao.insertStudent(student);
sqlSession.commit();
System.out.println("添加对象的数量:"+nums);
}
再看一个例子
Student
public interface StudentDao {
List<Student> selectStudentsByObject(Student student);
}
StudentDao.xml
<select id="selectStudentsByObject" resultType="BUPT.entity.Student">
select id, name, email, age
from student
where name=#{name} and id=#{id}
</select>
Test
@Test
public void SelectByObject(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
Student student = new Student();
student.setId(1008);
student.setName("李飞");
System.out.println("dao="+dao.getClass().getName());
//调用dao的方法, 执行数据库的操作
List<Student> students = dao.selectStudentsByObject(student);
for(Student stu: students){
System.out.println("学生="+stu);
}
}
按位置传值
按照StudentDao里面设置的接口参数的顺序
然后再StudentDao.xml中写配置文件时
写SQL语句时 where name=#{arg0} and age=#{arg1}
其中arg0代表第一个参数,arg1代表第二个
这样写可读性不是很强,不是很建议
Map传值
不常用,不建议
配置文件中写的是
where name=#{myname} and age=#{myage}
在测试方法中,建立map集合,其中的myname和myage都是map中的一个key
通过key找到对应map的value,传值给SQL语句
看着和传对象很像
比如数据写的是
Map<string,Object> data=new HashMap<>();
data.put("myname","zhangsan"};
data.put("myage",20};
就可以把data传过去
#号和$号
#:占位符,告诉 mybatis 使用实际的参数值代替。并使用 PrepareStatement 对象执行 sql 语句, #{…}代替sql 语句的“?”。 这样做更安全,更迅速,通常也是首选做法,防止SQL注入SQL注入参考博客
$ 字符串替换, 告诉 mybatis 使用$包含的“字符串”替换所在位置。使用 Statement 把 sql 语句和${}的
内容连接起来。主要用在替换表名,列名,不同列排序等操作
# 和 $区别
- #使用 ?在sql语句中做站位的, 使用PreparedStatement执行sql,效率高
- #能够避免sql注入,更安全。
- $不使用占位符,是字符串连接方式,使用Statement对象执行sql,效率低
- $有sql注入的风险,缺乏安全性。
- $:可以替换表名或者列名
定义别名
在mybatis主配置文件中定义,使用<typeAlias>定义别名
可以在resultType中使用自定义别名
之前在Student.xml中写的resultType都是全限定名称(当然推荐这样写)
<select id="selectStudentByTwoParams" resultType="BUPT.entity.Student">
select id, name, email, age
from student
where id = #{myid} and age=#{myage}
</select>
可以在MyBatis.xml设置自定义名称
<typeAliases>
<typeAlias type="BUPT.entity.Student" alias="MyStu"></typeAlias>
</typeAliases>
也可以写为
用package的方式,把包放进去,此时类名就是别名,不用写全限定名称
<typeAliases>
<package name="BUPT.entity"/>
</typeAliases>
当然还是建议使用全限定名称,因为可能不同包下有同名的类
resultMap
resultMap:结果映射, 指定列名和java对象的属性对应关系。
1)你自定义列值赋值给哪个属性
2)当你的列名和属性名不一样时,一定使用resultMap
resultMap和resultType不要一起用,二选一
模糊查询
一是 java 代码中给查询数据加上“%” ; 二是在 mapper 文件 sql 语句的条件位置加上“%”
方法一:java 代码中提供要查询的 “李%”
接口方法:
public List<Student> selectLikeFirst(String name);
mapper 文件:
<select id="selectLikeFirst" resultType="BUPT.entity.Student">
select id,name,email,age from student
where name like #{studentName}
</select>
测试方法:
@Test
public void testSelectLikeOne(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
String name="李%";
List<Student> stuList = dao.selectLikeFirst(name);
stuList.forEach( stu -> System.out.println(stu));
}
方法二:mapper 文件中使用 like name “%” #{xxx} “%”
接口方法:
public List<Student> selectLikeSecond(String name);
mapper 文件:
<select id="selectLikeSecond" resultType="BUPT.entity.Student">
select id,name,email,age from student
where name like #{studentName} "%"
</select>
测试方法:
@Test
public void testSelectLikeSecond() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
StudentDao dao = sqlSession.getMapper(StudentDao.class);
String name = "李";
List<Student> stuList = dao.selectLikeSecond(name);
stuList.forEach(stu -> System.out.println(stu));
}
结束时间:2021-12-08