MyBatis 接口代理方式实现 Dao 层
- 传统方式实现 Dao 层,我们既要写接口,还要写实现类。而 MyBatis 框架可以帮助我们省略编写 Dao 层接口实现类的步骤。程序员只需要编写接口,由 MyBatis 框架根据接口的定义来创建该接口的动态代理对象。
实现规则
- 映射配置文件中的名称空间必须和 Dao 层接口的全类名相同。
- 映射配置文件中的增删改查标签的 id 属性必须和 Dao 层接口的方法名相同。
- 映射配置文件中的增删改查标签的 parameterType 属性必须和 Dao 层接口方法的参数相同。
- 映射配置文件中的增删改查标签的 resultType 属性必须和 Dao 层接口方法的返回值相同。
获取动态代理对象
SqlSession 功能类中的 getMapper() 方法。
MyBatis 映射配置文件 - 动态 SQL
1.动态 SQL 指的就是 SQL 语句可以根据条件或者参数的不同进行动态的变化。
<where>:条件标签。
<if>:条件判断的标签。
<foreach>:循环遍历的标签。
2.我们可以将一些重复性的 SQL 语句进行抽取,以达到复用的效果。
<sql>:抽取 SQL 片段的标签。
<include>:引入 SQL 片段的标签。
数据准备
SQL
创建学生信息表
-- 创建学生表
CREATE TABLE student(
sid INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(20),
age INT
);
-- 添加信息
INSERT INTO student VALUES (NULL,'小付',25),(NULL,'小花花',18),(NULL,'李四',24);
准备项目
使用maven创建项目
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.fs</groupId>
<artifactId>MyBatis_day02_01</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- MyBatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!-- mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- log4j日志记录,可以在控制台输出sql语句方便我们查错-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- junit测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- lombok在实体类上注解@Data可以自动帮我们添加getset方法等-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>
</dependencies>
</project>
dao 接口
package com.fs.dao;
import com.fs.entity.Student;
import java.util.List;
/*
dao模拟
*/
public interface StudentMapper {
//查询所有学生信息
List<Student> findAll();
//更新学生信息
int updateStudent(Student student);
//多条件查询学生信息
List<Student> selectCondition(Student student);
//根据多个id查询学生信息
List<Student> selectByIds(List<Integer> ids);
//根据姓名查询学生
Student findStudentByName(String name);
}
Student实体类
package com.fs.entity;
import lombok.Data;
@Data //这个注解是lombok包下的,可以自动帮我们添加getset方法等
public class Student {
private Integer sid;
private String name;
private Integer age;
}
service 业务层
package com.fs.service;
import com.fs.entity.Student;
import java.util.List;
/*
Service层接口,模拟业务层
*/
public interface StudentService {
//下面的抽象方法与dao一样
List<Student> findAll();
int updateStudent(Student student);
List<Student> selectCondition(Student student);
List<Student> selectByIds(List<Integer> ids);
Student findStudentByName(String name);
}
业务层实现类
package com.fs.service.impl;
import com.fs.dao.StudentMapper;
import com.fs.entity.Student;
import com.fs.service.StudentService;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class StudentServiceImpl implements StudentService {
//声明Dao接口
private StudentMapper studentMapper;
//构造方法通过SqlSession的getMapper(接口的字节码)生成studentMapper代理类
public StudentServiceImpl() {
try {
//加载配置文件
InputStream rs = Resources.getResourceAsStream("MyBatisConfig.xml");
//获取工厂建造类
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//获取工厂对象
SqlSessionFactory build = sqlSessionFactoryBuilder.build(rs);
//获取SqlSession对象
SqlSession sqlSession = build.openSession(true);
//得到代理对象
studentMapper = sqlSession.getMapper(StudentMapper.class);
} catch (IOException e) {
e.printStackTrace();
}
}
/*
调用dao方法实现功能
*/
@Override
public List<Student> findAll() {
return studentMapper.findAll();
}
@Override
public int updateStudent(Student student) {
return studentMapper.updateStudent(student);
}
@Override
public List<Student> selectCondition(Student student) {
return studentMapper.selectCondition(student);
}
@Override
public List<Student> selectByIds(List<Integer> ids) {
return studentMapper.selectByIds(ids);
}
@Override
public Student findStudentByName(String name) {
return studentMapper.findStudentByName(name);
}
}
配置文件
数据库连接信息配置文件 jdbc.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://mysql服务器的ip地址:3306/创建student的库
username=root
password=root
log4j日志记录配置文件 log4j.properties
# Global logging configuration
# ERROR WARN INFO DEBUG
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
MyBatis核心配置文件 MyBatisConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!--MyBatis的DTD约束-->
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration 核心根标签-->
<configuration>
<!--引入数据库连接的配置文件-->
<properties resource="jdbc.properties"/>
<!--配置LOG4J-->
<settings>
<setting name="logImpl" value="log4j"/>
</settings>
<!--起别名-->
<typeAliases>
<!-- 给一个类起别名-->
<!-- <typeAlias type="com.fs.entity.Student" alias="student"/>-->
<!-- 给一个包下的类起别名,别名为类名的首字母小写-->
<package name="com.fs.entity"/>
</typeAliases>
<!--environments配置数据库环境,环境可以有多个。default属性指定使用的是哪个-->
<environments default="mysql">
<!--environment配置数据库环境 id属性唯一标识-->
<environment id="mysql">
<!-- transactionManager事务管理。 type属性,采用JDBC默认的事务-->
<transactionManager type="JDBC"></transactionManager>
<!-- dataSource数据源信息 type属性 连接池-->
<dataSource type="POOLED">
<!-- property获取数据库连接的配置信息 -->
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<!-- mappers引入映射配置文件 -->
<mappers>
<!-- mapper 引入指定的映射配置文件 resource属性指定映射配置文件的名称 -->
<mapper resource="StudentMapper.xml"/>
</mappers>
</configuration>
mapper映射配置文件,详细的介绍了动态sql常用的where标签if,foreach标签的使用
在映射配置文件中,MDL我只写了update,而insert,delete这两个和update没有任何区别,甚至标签体都可以混用,我们知道就好,但是实际开发还是什么需求用什么标签
<?xml version="1.0" encoding="UTF-8" ?>
<!--MyBatis的DTD约束-->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:dao接口的全限定名-->
<mapper namespace="com.fs.dao.StudentMapper">
<!-- 定义sql语句片段-->
<sql id="select">select <include refid="fields"></include> from</sql>
<!-- 将字段抽取出来,因为*会影响sql查询的速度-->
<sql id="fields">sid,name,age</sql>
<!-- 测试 用include标签来引用sql片段 select sid,name,age from student -->
<select id="findAll" resultType="student">
<include refid="select"></include> student
</select>
<!-- 根据name查找学生-->
<select id="findStudentByName" resultType="student">
select * from student where name = #{name}
</select>
<!-- 根据sid跟新学生对象-->
<update id="updateStudent">
update student set name = #{name},age = #{age} where sid = #{sid}
</update>
<!-- 动态sql-->
<select id="selectCondition" resultType="student">
<!-- where 标签的作用就是,自动添加where关键字,会自动将多余的and去掉-->
select * from student
<where>
<if test="sid != null">
sid = #{sid}
</if>
<if test="name != null">
and name = #{name}
</if>
<if test="age != null">
and age = #{age}
</if>
</where>
</select>
<!-- foreach标签 -->
<select id="selectByIds" resultType="student" parameterType="list">
select * from student
<!--
Collection:指定遍历的对象
open:遍历开始拼接的字符串
close:遍历结束后的字符串拼接
separator:每次拼接的分隔符
item:遍历得到的结果名
注意,如果传入的集合为空,就不会进行任何字符串拼接,包括open close
-->
<where>
<foreach collection="list" open="sid in(" separator="," close=")" item="sid">
#{sid}
</foreach>
</where>
</select>
</mapper>
测试类模拟controller层,控制台展示
package com.fs.dao;
import com.fs.entity.Student;
import com.fs.service.impl.StudentServiceImpl;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
public class StudentMapperTest {
/**
* 测试查询所有
*/
@Test
public void testFindAll() {
StudentServiceImpl studentService = new StudentServiceImpl();
List<Student> all = studentService.findAll();
for (Student student : all) {
System.out.println(student);
}
}
/**
* 更新学生信息
*/
@Test
public void testUpdate() {
StudentServiceImpl studentService = new StudentServiceImpl();
Student student1 = new Student();
student1.setAge(24);
student1.setName("张三");
student1.setSid(3);
int i = studentService.updateStudent(student1);
System.out.println("更新了:"+i+"条学生信息");
}
/**
* 根据多条件查询学生信息
*/
@Test
public void selectCondition() {
StudentServiceImpl studentService = new StudentServiceImpl();
Student student1 = new Student();
student1.setAge(24);
student1.setName("李四");
// student1.setSid(3);
List<Student> stu = studentService.selectCondition(student1);
for (Student student : stu) {
System.out.println(student);
}
}
/**
* 根据多个id查询
*/
@Test
public void selectByIds() {
StudentServiceImpl studentService = new StudentServiceImpl();
ArrayList<Integer> integers = new ArrayList<>();
integers.add(1);
integers.add(2);
integers.add(3);
List<Student> students = studentService.selectByIds(integers);
for (Student student : students) {
System.out.println(student);
}
}
/*
根据名字查询学生信息
*/
@Test
public void findStudentByName() {
StudentServiceImpl studentService = new StudentServiceImpl();
Student xh = studentService.findStudentByName("小花花");
System.out.println(xh);
}
}