原创
Mybatis的mapper动态代理
温馨提示:
本文最后更新于 2018年02月01日,已超过 2,489 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我。
1. 未使用mapper动态代理
工程截图
SQL
CREATE TABLE `t_student` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) NULL,
`age` INT NULL,
`score` DOUBLE NULL,
PRIMARY KEY (`id`));
pow
Maven导包。
<?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">
<parent>
<artifactId>ssm</artifactId>
<groupId>com.lzhpo.study</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>2-mybatis-improvement</artifactId>
<packaging>war</packaging>
<name>2-mybatis-improvement Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<finalName>2-mybatis-improvement</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
<!--如果不添加resources里面的内容的话,maven是不会将xml文件发布到编译后的classes目录下,这样就会导致mybatis到不到该文件。-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
Student
包含Getter/Setter、构造器、toString方法。
package com.lzhpo.bean;
import org.apache.ibatis.type.Alias;
/**
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
//@Alias("student")
public class Student {
private int id;
private String name;
private int age;
private double score;
/**
* 创建构造函数
* @param name
* @param age
* @param score
*/
//带id
public Student(int id, String name, int age, double score) {
this.id = id;
this.name = name;
this.age = age;
this.score = score;
}
//不带id
public Student(String name, int age, double score) {
this.name = name;
this.age = age;
this.score = score;
}
/**
* Setter/Getter
* @return
*/
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
/**
* toString
* @return
*/
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
}
StudentMapper.xml
里面是我们写的sql语句。
<?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">
<!--
namespace:命名空间。
id:方法,不能重复。
parameterType:传入参数类型。
-->
<mapper namespace="lzhpo">
<!--添加学生-->
<!--parameterType可省略-->
<insert id="insertStudent">
INSERT INTO t_student(name,age,score) VALUES (#{name},#{age},#{score})
<!--获取自增主键-->
<selectKey resultType="int" keyProperty="id" order="AFTER">
select @@identity
</selectKey>
</insert>
<!--删除学生-->
<delete id="deleteById">
delete from t_student where id=#{id}
</delete>
<!--更新操作-->
<update id="updateStudent">
update t_student set name=#{name},age=#{age},score=#{score} where id=#{id}
</update>
<!--查询所有-->
<!--注意:resultType要写上单条数据对应的类,查询中不要使用*,效率低下。-->
<select id="selectAllStudent" resultType="student">
select id,name,age,score from t_student
</select>
<!--查询单条-->
<select id="selectById" resultType="student">
select id,name,age,score from t_student where id=#{id}
</select>
<!--模糊查询(name)-->
<!--注意:另一种写法,不推荐,(SELECT id,name,age,score FROM t_student where name like '%${value}%')因为是字符串拼接,所以可能会引起sql注入的问题。-->
<select id="selectByName" resultType="student">
select id,name,age,score from t_student where name like '%' #{name} '%'
</select>
</mapper>
mybatis.xml
mybatis的全局配置文件。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--environment可配置多个(多数据源),id就要修改为不一样。
<environments default="development">:使用哪个environment。-->
<configuration>
<!--db.properties-->
<properties resource="db.properties"/>
<!--mybatis的别名,有顺序的,不能乱放位置。注册实体类的全限定名的别名。-->
<typeAliases>
<!--方式1:不方便,如果有多个,需要一个个写,效率低。 -->
<!--<typeAlias type="com.lzhpo.bean.Student" alias="student"/>-->
<!--方式2:mybatis会在这个包(com.lzhpo.bean)下搜索需要的bean;mybatis会自动的取别名,一般是首字母小写;
如果需要自己配置别名,就需要在com.lzhpo.bean.Student类中添加注解@Alias("student")-->
<package name="com.lzhpo.bean"/>
</typeAliases>
<!--environments:这里选择开发环境(development)-->
<environments default="development">
<!--1.开发环境-->
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
<!--2.测试环境-->
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.test.driver}"/>
<property name="url" value="${jdbc.test.url}"/>
<property name="username" value="${jdbc.test.username}"/>
<property name="password" value="${jdbc.test.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--注册映射文件-->
<mapper resource="com/lzhpo/dao/StudentMapper.xml"/>
</mappers>
</configuration>
db.properties
数据库的配置信息。
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/ssm?useUnicode=true&characterEncoding=utf-8&useSSL=false
jdbc.username=root
jdbc.password=123456
log4j.properties
打印日志消息的。
log4j.rootLogger=trace,console
#控制台附加器
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern= [%-5p][%d{yyyy-MM-dd HH:mm:ss}]%m%n
StudentDao
增删改查方法的接口。
package com.lzhpo.dao;
import com.lzhpo.bean.Student;
import java.util.List;
/**
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
public interface StudentDao {
//添加学生
void insertStudent(Student student);
//根据id删除学生
void deleteById(int id);
//删除学生
void updateStudent(Student student);
//查询所有学生数据
List<Student> selectAllStudent();
//根据id查询学生
Student selectStudentById(int id);
//模糊查询(name)
List<Student> selectByName(String name);
}
StudentDaoImpl
StudentDao的实现类。
package com.lzhpo.dao.impl;
import com.lzhpo.bean.Student;
import com.lzhpo.dao.StudentDao;
import com.lzhpo.util.MybatisUtil;
import org.apache.ibatis.session.SqlSession;
import java.util.List;
/**
* StudentDao的实现类
*
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
public class StudentDaoImpl implements StudentDao {
//创建成员变量sqlSession
private SqlSession sqlSession;
/**
* 添加学生
* @param student
*/
@Override
public void insertStudent(Student student) {
//SqlSession继承了AutoCloseable接口,所以可以自动关闭
SqlSession sqlSession = MybatisUtil.getSqlSession();
//新增数据库操作
sqlSession.insert("insertStudent",student);
//手动提交sqlSession事
// 要自动提交事务需要在MybatisUtil中 return sqlSessionFactory.openSession(true); 改为true。
sqlSession.commit();
}
/**
* 根据id删除学生
* @param id
*/
@Override
public void deleteById(int id) {
SqlSession sqlSession = MybatisUtil.getSqlSession();
sqlSession.delete("deleteById",id);
sqlSession.commit();
}
/**
* 更新学生
* @param student
*/
@Override
public void updateStudent(Student student) {
SqlSession sqlSession = MybatisUtil.getSqlSession();
sqlSession.update("updateStudent",student);
sqlSession.commit();
}
/**
* 查询所有学生
* @return
*/
@Override
public List<Student> selectAllStudent() {
List<Student> result = null;
SqlSession sqlSession = MybatisUtil.getSqlSession();
result = sqlSession.selectList("selectAllStudent");
return result;
}
/**
* 根据id查询
* @param id
* @return
*/
@Override
public Student selectStudentById(int id) {
Student student = null;
SqlSession sqlSession = MybatisUtil.getSqlSession();
student = sqlSession.selectOne("selectById",id);
return student;
}
/**
* 模糊查询(name)
* @param name
* @return
*/
@Override
public List<Student> selectByName(String name) {
List<Student> result = null;
SqlSession sqlSession = MybatisUtil.getSqlSession();
result = sqlSession.selectList("selectByName",name);
return result;
}
}
MybatisUtil
将过去SqlSession对象的操作封装成一个方法。SqlSession对象是由SqlSessionFactory对象创建的,SqlSessionFactory是线程安全的,所以可以使用单例模式来创建SqlSessionFactory对象。
package com.lzhpo.util;
/**
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
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;
/**
* DCL的单例模式
*/
public class MybatisUtil {
//不需要将构造方法私有化,因为这里的单例只是保证外界使用当前工具时创建一个SqlSessionFactory对象就行
// private MyBatisUtil() {
//
// }
private static volatile SqlSessionFactory sqlSessionFactory;
public static SqlSession getSqlSession() {
try {
if (sqlSessionFactory == null) {
//读取主配置文件
InputStream input = Resources.getResourceAsStream("mybatis.xml");
//线程安全锁机制,双重判断,保证new一个SqlSession
synchronized (MybatisUtil.class) {
if (sqlSessionFactory == null){
sqlSessionFactory = new SqlSessionFactoryBuilder().build(input);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return sqlSessionFactory.openSession();
}
}
Junit测试
package com.lzhpo.test;
import com.lzhpo.bean.Student;
import com.lzhpo.dao.StudentDao;
import com.lzhpo.dao.impl.StudentDaoImpl;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
/**
* Junit测试
*
* <p>
* Create By IntelliJ IDEA
* Author:lzhpo
* </p>
*/
public class StudentTest01 {
private StudentDao studentDao;
/**
* 所有操作都需要studentDao = new StudentDaoImpl();
* 直接写在Junit测试的Before
*/
@Before
public void initStudentDao(){
studentDao = new StudentDaoImpl();
}
/**
* 添加学生
*/
@Test
public void insertStudent(){
//Student student = new Student("鞠婧祎",25,100);
Student student1 = new Student("周大生",50,98);
//此时id为0
System.out.println(student1);
studentDao.insertStudent(student1);
//可以获取自增主键
System.out.println(student1);
}
/**
* 根据id删除学生
*/
@Test
public void deleteById(){
studentDao.deleteById(2);
}
/**
* 更新学生
*/
@Test
public void updateStudent(){
//创建更新后的学生
Student student2 = new Student("周杰伦",32,99);
//需要更新哪个学生
student2.setId(4);
//调用studeDao里面的方法
studentDao.updateStudent(student2);
}
/**
* 查询所有学生
*/
@Test
public void selectAllStudent(){
List<Student> studentList = studentDao.selectAllStudent();
//java8新增的Lambda表达式
studentList.forEach((s ->{
System.out.println(s);
}));
}
/**
* 根据id查询
*/
@Test
public void selectById(){
Student student = studentDao.selectStudentById(1);
System.out.println(student);
}
/**
* 模糊查询(name)
*/
@Test
public void selectByName(){
List<Student> studentList = studentDao.selectByName("周");
studentList.forEach((s -> {
System.out.println(s);
}));
}
}
2. 使用mapper动态代理
mapper的动态代理介绍
在之前的例子中,我们在dao接口的实现类中写了一些获取sqlSession并调用其方法的代码,这些代码实际上没有什么实质的作用,具体SQL方面的操作我们都写在mapper文件中了,因此可以mybatis抛开这些实现类,以后无需编写这些实现类了,直接通过dao接口来定位到mapper中的SQL语句,这种方式被称为mapper的动态代理。
如何使用?
将上面的StudentDaoImpl(StudentDao的实现类)删除
这些代码实际上没有什么实质的作用,具体SQL方面的操作我们都写在mapper文件中了,因此可以mybatis抛开这些实现类,以后无需编写这些实现类了,直接通过dao接口来定位到mapper中的SQL语句。
修改StudentMapper.xml
的命名空间
<mapper namespace="lzhpo">修改为<mapper namespace="com.lzhpo.dao.StudentDao">
如下:
<mapper namespace="com.lzhpo.dao.StudentDao">
这样子mybatis会自动和com.lzhpo.dao.StudentDao
一一对应。
修改Junit测试类
添加SqlSession和StudentDao的成员变量,将之前的@Before
和@After
修改。
private SqlSession sqlSession;
private StudentDao studentDao;
/**
* 测试时先执行该方法创建StudentDao对象
*/
@Before
public void initStudentDao(){
sqlSession = MybatisUtil.getSqlSession();
//通过该方法可以获取StudentDao的对象
studentDao = sqlSession.getMapper(StudentDao.class);
}
/**
* 执行完成后需要关闭sqlSession
*/
@After
public void closeSession() {
if (sqlSession != null) {
sqlSession.close();
}
}
Mybatis的mapper动态代理总结
- 在开发的过程中只需要写Dao层的借口,无需写其实现类,实现类有框架自己补充。
- 不需要写Dao层的实现类,减轻程序员的压力,简化代码。
- 本文标签: Mybatis Java SpringBoot
- 本文链接: http://www.lzhpo.com/article/45
- 版权声明: 本文由lzhpo原创发布,转载请遵循《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权