MyBatis学习
一、MyBatis简介
0、MyBatis官方中文文档
1、MyBatis
- 和数据库进行交互
- 持久化层框架(SQL映射框架)
- 半自动框架
- 前身是iBatis
2、持久化层技术
- 原始的JDBC–>dbutils(QueryRunner)–>JdbcTemplate–>等等
称为工具
- 一些功能的简单封装
框架
- 某些领域的整体解决方案
- 要考虑缓存,异常处理问题,部分字段映射问题等
不用原生JDBC原因
-
麻烦(使用流程)

-
sql语句是硬编码在程序中的
- 耦合(数据库层和java编码耦合)
3、Hibernate
- 数据库库交互的框架(ORM框架)
- ORM(Object Relation Mapping)对象关系映射
- 全自动的框架
1.优点
- 方便

2.缺点
- 无法定制sql(二八理论)
- 要学HQL(Hibernate Query Language)(反模式)
- 全映射框架(做部分字段映射很难)
希望
- 最好有一个框架
- 支持定制化sql
- 功能强大
- sql也不要硬编码在java文件中(导致维护修改起来比较麻烦)
4、MyBatis应运而生
-
MyBatis将重要的步骤抽取出来可以人工定制,其他步骤自动化

-
重要步骤都是写在配置文件中(好维护)
-
完全解决数据库的优化问题
-
MyBatis底层就是对原生JDBC的一个简单封装
-
既将java编码与sql抽取了出来,还不会失去自动化功能(半自动化的持久化层框架)
-
mybatis是一个轻量级的框架
二、HelloWorld
1、环境搭建
1.创建一个java工程
2.创建测试库
- 测试表,封装数据的javaBean和操作数据库的dao接口
3.用MyBatis操作数据库
1、导包(建议导入日志包)
mybatis-3.5.6.jar
mysql-connector-java-8.0.22.jar
log4j-1.2.17.jar(可选)
- log4j(日志框架):依赖类路径下一个log4j.xml配置文件
2、写配置
-
第一个配置文件(==全局配置文件==)(mybatis-config.xml)
- ==指导mybatis==正确==运行==的一些全局设置(比如连接哪个数据库)
-
第二个配置文件(==SQL映射文件==)(EmployeeDao.xml)
-
编写每一个方法如何向数据库发送sql语句,如何执行(相当于==对Dao接口的一个实现描述==)
-
将mapper的namespace属性改为接口的全类名
-
配置细节
<!-- namespace:名称空间,写接口的全类名;相当于告诉MyBatis这个配置文件是实现哪个接口的 --> <mapper namespace="com.lql.dao.EmployeeDao"> <!-- public Employee getEmpById(Integer id); --> <!-- select:用来定义一个查询操作; id:方法名,相当于这个配置是对于某个方法的实现 resultType:指定方法运行后的返回值类型(查询操作必须指定的) #{属性名}:代表取出传递过来的某个参数的值 --> <select id="getEmpById" resultType="com.lql.bean.Employee"> select * from employee where id = #{id} </select> </mapper> -
我们写的dao接口的实现文件,mybatis默认是不知道的,需要在全局配置文件中注册
<!-- 引入我们自己编写的每一个接口的实现文件 --> <mappers> <!-- resource:表示从类路径下找资源 --> <mapper resource="mybatis/EmployeeDao.xml"/> </mappers>
-
-
3、测试
-
根据全局配置文件先创建一个SqlSessionFactory
//1、根据全局配置文件创建出一个SqlSessionFactory //SqlSessionFactory:是SqlSession工厂,负责创建SqlSession对象 //SqlSession:sql会话(代表和数据库的一次会话) String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
-
sqlSessionFactory中获取sqlSession对象操作数据库即可
//2、获取和数据库的一次会话:getConnection(); SqlSession openSession = sqlSessionFactory.openSession(); //3、使用SqlSession操作数据库,先获取到dao接口的实现 EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class); //4、调用之前的方法 Employee employee = employeeDao.getEmpById(1); System.out.println(employee);
-
==注意==:测试可能会出现时区错误,是数据库版本的问题,可参考解决办法
4、总体架构:

5、mybatis-config.xml
<?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">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!-- 配置连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 引入我们自己编写的每一个接口的实现文件 -->
<mappers>
<!-- resource:表示从类路径下找资源 -->
<mapper resource="mybatis/EmployeeDao.xml"/>
</mappers>
</configuration>
6、log4j.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<param name="Encoding" value="UTF-8" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" />
</layout>
</appender>
<logger name="java.sql">
<level value="debug" />
</logger>
<logger name="org.apache.ibatis">
<level value="info" />
</logger>
<root>
<level value="debug" />
<appender-ref ref="STDOUT" />
</root>
</log4j:configuration>
7、EmployeeDao.xml
<?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:名称空间,写接口的全类名;相当于告诉MyBatis这个配置文件是实现哪个接口的 -->
<mapper namespace="com.lql.dao.EmployeeDao">
<!-- public Employee getEmpById(Integer id); -->
<!-- select:用来定义一个查询操作;
id:方法名,相当于这个配置是对于某个方法的实现
resultType:指定方法运行后的返回值类型(查询操作必须指定的)
#{属性名}:代表取出传递过来的某个参数的值
-->
<select id="getEmpById" resultType="com.lql.bean.Employee">
select * from employee where emp_id = #{emp_id}
</select>
</mapper>
8、MyBatisTest.java
package com.lql.test;
import java.io.IOException;
import java.io.InputStream;
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 org.junit.Test;
import com.lql.bean.Employee;
import com.lql.dao.EmployeeDao;
public class MyBatisTest {
@Test
public void test() throws IOException {
//1、根据全局配置文件创建出一个SqlSessionFactory
//SqlSessionFactory:是SqlSession工厂,负责创建SqlSession对象
//SqlSession:sql会话(代表和数据库的一次会话)
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//4、调用之前的方法
Employee employee;
//2、获取和数据库的一次会话:getConnection();
SqlSession openSession = sqlSessionFactory.openSession();
try {
//3、使用SqlSession操作数据库,先获取到dao接口的实现
EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class);
employee = employeeDao.getEmpById(1);
} finally {
openSession.close();
}
System.out.println(employee);
}
}
9、EmployeeDao.java
package com.lql.dao;
import com.lql.bean.Employee;
public interface EmployeeDao {
//数据库驱动
//mysql-connector-java-8.0.22.jar
//mybatis-3.5.6.jar
//log4j-1.2.17.jar
//按照员工id查询员工
public Employee getEmpById(Integer id);
}
10、Employee.java
package com.lql.bean;
public class Employee {
private Integer emp_id;
private String emp_name;
private Integer emp_gender;
private String emp_email;
public Integer getEmp_id() {
return emp_id;
}
public void setEmp_id(Integer emp_id) {
this.emp_id = emp_id;
}
public String getEmp_name() {
return emp_name;
}
public void setEmp_name(String emp_name) {
this.emp_name = emp_name;
}
public Integer getEmp_gender() {
return emp_gender;
}
public void setEmp_gender(Integer emp_gender) {
this.emp_gender = emp_gender;
}
public String getEmp_email() {
return emp_email;
}
public void setEmp_email(String emp_email) {
this.emp_email = emp_email;
}
@Override
public String toString() {
return "Employee [emp_id=" + emp_id + ", emp_name=" + emp_name + ", emp_gender=" + emp_gender + ", emp_email="
+ emp_email + "]";
}
}
2、如何写xml有提示
让eclipse找到dtd约束文件的位置
-
dtd约束文件(mybatis jar包中解压复制出来)

-
绑定约束文件的位置
- 复制dtd的引用网址
- eclipse进入window–》perferences–》XML–》XML Catalog
- 点击Add,Location写dtd约束文件的位置,Key type 选URI,Key填复制的引用网址
- 点击🆗,完事。

3、细节
1.获取到的是接口的代理对象
- mybatis自动创建的
2.SqlSessionFactory和SqlSession
- SqlSessionFactory创建SqlSession对象,Factory只new一次就行
- SqlSession相当于connection和数据库进行交互
- 和数据库的一次会话
- 应该创建一个新的sqlSession
三、全局配置文件
1、mybatis-config.xml
2、配置文档的顶层结构
-
configuration(配置)
- properties(属性)
- settings(设置)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- environments(环境配置)
- environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
- environment(环境变量)
- databaseIdProvider(数据库厂商标识)
- mappers(映射器)
-
建议参考MyBatis官方中文文档
3、原生jdbc执行sql
- 或者封装结果集
Connection connection = dataSource.getConnection();
String sql = "insert into employee(emp_name,emp_email,emp_gender) values(?,?,?)";
PreparedStatement ps = connection.prepareStatement(sql);
ps.setString(0,"admin");
ps.setString(1,"aaa@qq.com");
ps.setInt(2,1);
int i = ps.executeUpdate();
//ps.close();connection.close();
4、增删改查测试
1.EmployeeDao.java
package com.lql.dao;
import com.lql.bean.Employee;
public interface EmployeeDao {
public Employee getEmpById(Integer emp_id);
public int updateEmployee(Employee employee);
public boolean deleteEmployee(Integer emp_id);
public int insertEmployee(Employee employee);
}
2.EmployeeDao.xml
<?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">
<mapper namespace="com.lql.dao.EmployeeDao">
<!-- public Employee getEmpById(Integer emp_id);参数类型不用写 -->
<select id="getEmpById" resultType="com.lql.bean.Employee">
<!-- sql语句不要写分号 -->
select * from employee where emp_id=#{emp_id}
</select>
<!-- public int updateEmployee(Employee employee);
增删改不用写返回值类型;增删改是返回影响多少行
mybatis自动判断,如果是数字(int,long)
如果是boolean(影响0行自动封装false,否则true)
#{属性名}:从传入的参数对象中取出对应属性的值
-->
<update id="updateEmployee">
UPDATE employee
SET emp_name=#{emp_name},emp_gender=#{emp_gender},emp_email=#{emp_email}
WHERE emp_id=#{emp_id}
</update>
<!-- public int deleteEmployee(Integer emp_id); -->
<delete id="deleteEmployee">
DELETE FROM employee WHERE emp_id=#{emp_id}
</delete>
<!-- public int insertEmployee(Employee employee);-->
<insert id="insertEmployee">
INSERT INTO employee(emp_name,emp_gender,emp_email)
VALUES(#{emp_name},#{emp_gender},#{emp_email})
</insert>
</mapper>
3.MyBatisCRUDTest.java
package com.lql.test;
import java.io.IOException;
import java.io.InputStream;
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 org.junit.Before;
import org.junit.Test;
import com.lql.bean.Employee;
import com.lql.dao.EmployeeDao;
public class MyBatisCRUDTest {
//工厂一个
SqlSessionFactory sqlSessionFactory;
@Before
public void initSqlSessionFactory() throws IOException{
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
/**
* 测试添加
*/
@Test
public void testInsert(){
//1、获取和数据库的一次会话
//true:代表自动提交
SqlSession openSession = sqlSessionFactory.openSession(true);
try {
//2、获取到接口的映射器
EmployeeDao mapper = openSession.getMapper(EmployeeDao.class);
//3、测试
int i = mapper.insertEmployee(new Employee(null, "tomcat", 0, "tomcat@qq.com"));
System.out.println(i);
} finally {
//手动提交
//openSession.commit();
openSession.close();
}
}
/**
* 测试删除
*/
@Test
public void testDelete(){
//1、获取和数据库的一次会话
//true:代表自动提交
SqlSession openSession = sqlSessionFactory.openSession(true);
try {
//2、获取到接口的映射器
EmployeeDao mapper = openSession.getMapper(EmployeeDao.class);
//3、测试
mapper.deleteEmployee(4);
} finally {
//手动提交
//openSession.commit();
openSession.close();
}
}
/**
* 测试修改
*/
@Test
public void testUpdate(){
//1、获取和数据库的一次会话
//true:代表自动提交
SqlSession openSession = sqlSessionFactory.openSession(true);
try {
//2、获取到接口的映射器
EmployeeDao mapper = openSession.getMapper(EmployeeDao.class);
//3、测试
int i = mapper.updateEmployee(new Employee(5, "tom", 1, "tom@qq.com"));
System.out.println(i);
} finally {
//手动提交
//openSession.commit();
openSession.close();
}
}
/**
* 测试查询
* @throws IOException
*/
@Test
public void test() throws IOException {
//1、根据全局配置文件得到SqlSessionFactory对象
//initSqlSessionFactory();
//2、得到SqlSession对象;
SqlSession openSession = sqlSessionFactory.openSession();
//3、获取到dao接口的实现(映射器)
EmployeeDao dao = openSession.getMapper(EmployeeDao.class);
//class com.sun.proxy.$Proxy7
System.out.println(dao.getClass());
try {
Employee employee = dao.getEmpById(1);
System.out.println(employee);
} finally {
openSession.close();
}
}
}
5、MyBatis_config工程
- ==注解配置配合使用==(重要的dao写配置,简单的dao就直接标注解)
1.总体架构:

2.mybatis-config.xml
<?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">
<configuration>
<!-- 1、和Spring的context:property-placeholder(引用配置文件)相同 -->
<!--
resource:从类路径下开始引用
url:引用磁盘路径或者网络路径的资源
-->
<properties resource="dbconfig.properties">
<property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/>
</properties>
<!-- 2、settings是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 -->
<settings>
<!-- name:配置项的key,value:配置项的值 -->
<!-- loginAccount ==》login_account -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!-- 3、类型别名,为常用的类型(javaBean)起别名 -->
<typeAliases>
<!-- typeAlias:就是为一个JavaBean起别名,别名默认就是类名(不区分大小写),配置文件中就可以用别名了 -->
<!-- alias="":指定一个别名 -->
<!-- <typeAlias type="com.lql.bean.Employee" alias="emp"/> -->
<!-- 批量起别名;name=""指定包名,默认别名就是类名 -->
<!-- <package name="com.lql.bean"/> -->
<!-- 我们推荐就用全类名 -->
</typeAliases>
<!-- 4、类型处理器,作用: -->
<!-- <typeHandlers>
自定义好的类型处理器就这么配置上就行了
<typeHandler handler=""/>
</typeHandlers> -->
<!-- 5、插件是mybatis中的一个强大功能 -->
<!-- 6、environments配置环境“们”
environment:配置一个具体的环境,都需要一个事务管理器和一个数据源
transactionManger
后来的数据源和事务管理都是Spring来管理
-->
<!-- default="development":默认使用哪个环境 -->
<environments default="development">
<!-- id="testEnv"是当前环境的唯一标识 -->
<environment id="testEnv">
<transactionManager type=""/>
<dataSource type="">
<property name="driver" value="jdbc:mysql://47.110.152.31:3333/user_db"/>
<property name="url" value="${jdbcurl}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
<environment id="development">
<transactionManager type="JDBC"/>
<!-- 配置连接池 -->
<dataSource type="POOLED">
<!-- ${}取出配置文件中的值 -->
<property name="driver" value="${driverclass}"/>
<property name="url" value="${jdbcurl}"/>
<property name="username" value="${username:root}"/><!-- 如果属性 'username' 没有被配置,'username' 属性的值将为 'root' -->
<property name="password" value="${password:123456}"/>
</dataSource>
</environment>
</environments>
<!-- 7、mybatis用来考虑数据库移植性的 -->
<databaseIdProvider type="DB_VENDOR">
<!-- name="":数据库厂商标识;value="":给这个标识起一个好用的名字
MySQL、Oracle、SQL Server
-->
<property name="MySQL" value="mysql"/>
<property name="SQL Server" value="sqlserver"/>
<property name="Oracle" value="oracle"/>
</databaseIdProvider>
<!-- 8、写好的sql映射文件,需要使用mappers注册进来 -->
<mappers>
<!--
url:可以从磁盘或者网络路径引用
resource:在类路径下找sql映射文件
class:直接引用接口的全类名
可以将xml放在和dao接口同目录下,而且文件名和接口名一致;
class的另一种用法
-->
<!-- <mapper class="com.lql.dao.EmployeeDao"/> -->
<!-- <mapper class="com.lql.dao.EmployeeDaoAnnotation"/>
<mapper resource="mybatis/EmployeeDao.xml"/> -->
<!-- 配合使用:重要的dao可以写配置;
简单的dao就直接标注解;
-->
<!-- 批量注册 name="":dao所在的包名 -->
<package name="com.lql.dao"/>
</mappers>
</configuration>
3.dbconfig.properties
username=root
password=123456
jdbcurl=jdbc:mysql://localhost:3306/test?serverTimezone=UTC
driverclass=com.mysql.cj.jdbc.Driver
4.EmployeeDao.xml
<?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">
<mapper namespace="com.lql.dao.EmployeeDao">
<!-- public Employee getEmpById(Integer emp_id);参数类型不用写 -->
<!-- 默认这个查询是不区分环境 -->
<select id="getEmpById" resultType="com.lql.bean.Employee">
<!-- sql语句不要写分号 -->
select * from employee where emp_id=#{emp_id}
</select>
<!-- 如果能精确匹配就精确,不能就用模糊的 -->
<select id="getEmpById" resultType="com.lql.bean.Employee" databaseId="mysql">
<!-- sql语句不要写分号 -->
select * from employee where emp_id=#{emp_id}
</select>
<select id="getEmpById" resultType="com.lql.bean.Employee" databaseId="oracle">
<!-- sql语句不要写分号 -->
select * from employee where emp_id=#{emp_id}
</select>
<!-- public int updateEmployee(Employee employee);
增删改不用写返回值类型;增删改是返回影响多少行
mybatis自动判断,如果是数字(int,long)
如果是boolean(影响0行自动封装false,否则true)
#{属性名}:从传入的参数对象中取出对应属性的值
-->
<update id="updateEmployee">
UPDATE employee
SET emp_name=#{emp_name},emp_gender=#{emp_gender},emp_email=#{emp_email}
WHERE emp_id=#{emp_id}
</update>
<!-- public int deleteEmployee(Integer emp_id); -->
<delete id="deleteEmployee">
DELETE FROM employee WHERE emp_id=#{emp_id}
</delete>
<!-- public int insertEmployee(Employee employee);-->
<insert id="insertEmployee">
INSERT INTO employee(emp_name,emp_gender,emp_email)
VALUES(#{emp_name},#{emp_gender},#{emp_email})
</insert>
</mapper>
4.MyBatisCRUDTest.java
package com.lql.test;
import java.io.IOException;
import java.io.InputStream;
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 org.junit.Before;
import org.junit.Test;
import com.lql.bean.Employee;
import com.lql.dao.EmployeeDao;
import com.lql.dao.EmployeeDaoAnnotation;
public class MyBatisCRUDTest {
//工厂一个
SqlSessionFactory sqlSessionFactory;
@Before
public void initSqlSessionFactory() throws IOException{
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testAnnotation(){
SqlSession openSession = sqlSessionFactory.openSession();
EmployeeDaoAnnotation mapper = openSession.getMapper(EmployeeDaoAnnotation.class);
Employee empById = mapper.getEmpById(5);
System.out.println(empById);
EmployeeDao mapper2 = openSession.getMapper(EmployeeDao.class);
System.out.println(mapper2);
Employee empById2 = mapper2.getEmpById(1);
System.out.println(empById2);
}
5.EmployeeDaoAnnotation.java
package com.lql.dao;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import com.lql.bean.Employee;
public interface EmployeeDaoAnnotation {
@Select("select * from employee where emp_id=#{emp_id}")
public Employee getEmpById(Integer emp_id);
@Update("UPDATE employee "
+ "SET emp_name=#{emp_name},emp_gender=#{emp_gender},emp_email=#{emp_email}"
+ " WHERE emp_id=#{emp_id}")
public int updateEmployee(Employee employee);
@Delete("DELETE FROM employee WHERE emp_id=#{emp_id}")
public boolean deleteEmployee(Integer emp_id);
@Insert("INSERT INTO employee(emp_name,emp_gender,emp_email) "
+ "VALUES(#{emp_name},#{emp_gender},#{emp_email})")
public int insertEmployee(Employee employee);
}
四、SQL映射文件
- 映射文件指导着MyBatis如何进行数据库增删改查,有着非常重要的意义
1、增删改元素

2、各种配置
3、MyBatis_sqlMapper
1.总体架构:

2.bean
package com.lql.bean;
public class Cat {
private Integer id;
private String name;
private Integer age;
private Integer gender;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getGender() {
return gender;
}
public void setGender(Integer gender) {
this.gender = gender;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Cat [id=" + id + ", name=" + name + ", age=" + age + ", gender=" + gender + "]";
}
}
*****************************************************
package com.lql.bean;
import org.apache.ibatis.type.Alias;
@Alias("emp")
public class Employee {
private Integer emp_id;
private String emp_name;
private Integer emp_gender;
private String emp_email;
public Employee() {
super();
}
public Employee(Integer emp_id, String emp_name, Integer emp_gender, String emp_email) {
super();
this.emp_id = emp_id;
this.emp_name = emp_name;
this.emp_gender = emp_gender;
this.emp_email = emp_email;
}
public Integer getEmp_id() {
return emp_id;
}
public void setEmp_id(Integer emp_id) {
this.emp_id = emp_id;
}
public String getEmp_name() {
return emp_name;
}
public void setEmp_name(String emp_name) {
this.emp_name = emp_name;
}
public Integer getEmp_gender() {
return emp_gender;
}
public void setEmp_gender(Integer emp_gender) {
this.emp_gender = emp_gender;
}
public String getEmp_email() {
return emp_email;
}
public void setEmp_email(String emp_email) {
this.emp_email = emp_email;
}
@Override
public String toString() {
return "Employee [emp_id=" + emp_id + ", emp_name=" + emp_name + ", emp_gender=" + emp_gender + ", emp_email="
+ emp_email + "]";
}
}
*****************************************************
package com.lql.bean;
/**
* 🔑表
* @author 陆乾龙
*
*/
public class Key {
private Integer id;//钥匙的id
private String keyName;//钥匙名
private Lock lock;//当前钥匙能开哪个锁
public Lock getLock() {
return lock;
}
public void setLock(Lock lock) {
this.lock = lock;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getKeyName() {
return keyName;
}
public void setKeyName(String keyName) {
this.keyName = keyName;
}
@Override
public String toString() {
return "Key [id=" + id + ", keyName=" + keyName + ", lock=" + lock + "]";
}
}
*****************************************************
package com.lql.bean;
import java.util.List;
/**
* 🔒表
* @author 陆乾龙
*
*/
public class Lock {
private Integer id;
private String lockName;
//查🔒的时候把所有的🔑也查出来
private List<Key> keys;
//1-1关联 1-n关联 n-n关联
/**
* 一个key开一把lock:1-1
* 一个lock有多把key:1-n
* 从key表看lock:n-1
* 1-n,n-1,n-n:外键应该放在哪个表?
* 一对多:外键一定放在多的一端
* 多对多:中间表存储对应关系
*/
public List<Key> getKeys() {
return keys;
}
public void setKeys(List<Key> keys) {
this.keys = keys;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getLockName() {
return lockName;
}
public void setLockName(String lockName) {
this.lockName = lockName;
}
@Override
public String toString() {
return "Lock [id=" + id + ", lockName=" + lockName + ", keys=" + keys + "]";
}
}
3.dao
package com.lql.dao;
import com.lql.bean.Cat;
public interface CatDao {
public Cat getCatById(Integer id);
}
*****************************************************
package com.lql.dao;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Param;
import com.lql.bean.Employee;
public interface EmployeeDao {
//列名作为key,值作为value
public Map<String, Object> getEmpByIdReturnMap(Integer emp_id);
public List<Employee> getAllEmps();
/**
* key就是这个记录的主键,value就是这条记录封装好的对象;
* @return
*
* 把查询的记录的id的值作为key封装这个map:
* @MapKey("emp_id")
*/
@MapKey("emp_id")
public Map<Integer, Employee> getAllEmpsReturnMap();
public Employee getEmpById(Integer emp_id);
public Employee getEmpByIdAndEmpName(@Param("emp_id")Integer emp_id,@Param("emp_name")String emp_name);
public Employee getEmpByIdAndEmpName1(Map<String, Object> map);
public int updateEmployee(Employee employee);
public boolean deleteEmployee(Integer emp_id);
public int insertEmployee(Employee employee);
public int insertEmployee2(Employee employee);
}
*****************************************************
package com.lql.dao;
import java.util.List;
import com.lql.bean.Key;
public interface KeyDao {
/**
* 将🔑和🔒ℹ一起查出
* @param id
* @return
*/
public Key getKeyById(Integer id);
public Key getKeyByIdSimple(Integer id);
public List<Key> getKeysByLockId(Integer id);
}
*****************************************************
package com.lql.dao;
import com.lql.bean.Lock;
public interface LockDao {
//查🔒的时候将所有🔑也查出来
public Lock getLockById(Integer id);
public Lock getLockByIdSimple(Integer id);
public Lock getLockByIdByStep(Integer id);
}
4.dao.xml
&&&&&&&&&&&&&&&&&&&&&&& CatDao.xml &&&&&&&&&&&&&&&&&
<?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">
<mapper namespace="com.lql.dao.CatDao">
<!-- getCatById(Integer)
resultType="com.lql.bean.Cat":使用默认规则:属性列名一一对应
resultMap="mycat":查出数据封装结果的时候,使用mycat自定义的规则
-->
<select id="getCatById" resultMap="mycat">
<!-- select id,cname name,cage age,cgender gender from t_cat where id=#{id} -->
select * from t_cat where id=#{id}
</select>
<!-- 自定义结果集:自己定义每一列数据和javaBean的映射规则
type="":指定为哪个javaBean自定义封装规则;全类名
id="":唯一标识,让别名在后面引用
-->
<resultMap type="com.lql.bean.Cat" id="mycat">
<!-- 指定主键列的对应规则:
column="id":指定那一列是主键列
property="":指定cat的哪个属性封装id这一列数据
-->
<id property="id" column="id"/>
<!-- 普通列 -->
<result property="name" column="cname"/>
<result property="age" column="cage"/>
<result property="gender" column="cgender"/>
</resultMap>
</mapper>
&&&&&&&&&&&&&&&&&&&&&&& EmployeeDao.xml &&&&&&&&&&&&
<?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">
<mapper namespace="com.lql.dao.EmployeeDao">
<!-- namespace="com.lql.dao.EmployeeDao":写dao接口的全类名 -->
<!-- 这个文件中能写的所有标签:
cache:和缓存有关
cache-ref:和缓存有关
parameterMap:参数map;废弃的。。。原本是来做复杂参数映射的;
resultMap:结果集映射;自定义结果集的封装规则
sql:抽取可重用的sql;
delete、update、insert、select:增删改查;
databaseId:指定这个CRUD属于哪个数据库的
-->
<!-- public int insertEmployee(Employee employee);-->
<!--
让MyBatis自动的将自增id赋值给传入的employee对象的id属性
useGeneratedKeys="true":原生jdbc获取自增主键的方法;
keyProperty="":将刚才自增的id封装给哪个属性
-->
<insert id="insertEmployee" useGeneratedKeys="true" keyProperty="emp_id">
<!-- 查询主键
order="BEFORE":
在核心sql语句之前先运行一个查询sql查到id;将查到的id赋值给javaBean的哪个属性
-->
<selectKey order="BEFORE" keyProperty="emp_id">
select max(emp_id) from employee
</selectKey>
INSERT INTO employee(emp_name,emp_gender,emp_email)
VALUES(#{emp_name},#{emp_gender},#{emp_email})
</insert>
<!-- public int insertEmployee2(Employee employee); -->
<insert id="insertEmployee2">
<!-- 查询主键
order="BEFORE":
在核心sql语句之前先运行一个查询sql查到id;将查到的id赋值给javaBean的哪个属性
-->
<selectKey order="BEFORE" resultType="integer" keyProperty="emp_id">
select max(emp_id)+1 from employee
</selectKey>
INSERT INTO employee(emp_id,emp_name,emp_gender,emp_email)
VALUES(#{emp_id},#{emp_name},#{emp_gender},#{emp_email})
</insert>
<update id="updateEmployee" >
UPDATE employee
SET emp_name=#{emp_name},emp_gender=#{emp_gender},emp_email=#{emp_email}
WHERE emp_id=#{emp_id}
</update>
<!-- public int deleteEmployee(Integer emp_id); -->
<delete id="deleteEmployee" >
DELETE FROM employee WHERE emp_id=#{emp_id}
</delete>
<!-- 传参到底能传哪些 -->
<!-- public Employee getEmpById(Integer emp_id); -->
<select id="getEmpById" resultType="com.lql.bean.Employee" >
select * from employee where emp_id=#{hahaha}
</select>
<!-- Caused by: org.apache.ibatis.binding.BindingException:
Parameter 'emp_id' not found.
Available parameters are [arg1, arg0, param1, param2]
-->
<!-- public Employee getEmpByIdAndEmpName(Integer emp_id,String emp_name); -->
<select id="getEmpByIdAndEmpName" resultType="com.lql.bean.Employee">
select * from employee where emp_id=#{emp_id} and emp_name=#{emp_name}
</select>
<!-- public Employee getEmpByIdAndEmpName1(Map<String, Object> map); -->
<select id="getEmpByIdAndEmpName1" resultType="com.lql.bean.Employee">
select * from ${tableName} where emp_id=#{emp_id,jdbcType=INTEGER} and emp_name=#{emp_name}
</select>
<!-- 现象:
1)、单个参数
基本类型:
取值:#{随便写}
传入Pojo
2)、多个参数
public Employee getEmpByIdAndEmpName(Integer emp_id,String emp_name)
取值:#{参数名}是无效了;
可用:arg0,arg1或者param1,param2
原因:只要是传入了多个参数;mybatis会自动的将这些参数封装在一个map中,
封装时使用的key就是参数的索引和参数的第几个表示
Map<String,Object> map = new HashMap<>();
map.put("1",传入的值);map.put("2",传入的值);
#{key}就是从这几个map中取值;
3)、@Param("")为参数指定key,命名参数,我们以后也推荐这么做;
我们可以告诉mybatis,封装参数map的时候别乱来,使用我们指定的key
4)、传入了pojo(javaBean)
取值:#{pojo的属性名}
5)、传入了map;将多个要使用的参数封装起来
取值:#{key}
扩展:多个参数:自动封装map;
method01(@Param("emp_id")Integer emp_id,String emp_name,Employee employee);
Integer id -> #{emp_id}
String emp_name -> #{param2}
Employee employee(取出这里面的email) -> #{param3.email}
无论传入什么参数都要能正确的取出值;
#{key/属性名}
1)、#{key,jdbcType=INTEGER};
javaType、jdbcType、mode、numericScale、resultMap、typeHandler、jdbcTypeName、expression
只有jdbcType才可能是需要被指定的;
默认不指定jdbcType:mysql没问题,oracle没问题;
万一传入的数据是null:mysql插入null没问题,【oracle不知道null到底是什么类型】
实际上在mybatis中,有两种取值方式:
#{属性名}:是预编译的方式,参数的位置都是?替代,参数后来都是预编译设置进去的;安全,不会有sql注入问题
${属性名}:不是参数预编译,而是直接和sql语句进行拼串;不安全:
//emp_id=1 or 1=1 or and emp_name=
传入一个'1 or 1=1 or'
有使用场景:sql语句只有参数位置是支持预编译的:
log_2020_12、log_2021_1(动态表名)
select * from log_2021_1 where emp_id=1 and emp_name=?
emp_id=${emp_id} and emp_name=#{emp_name}
select * from employee where emp_id=1 and emp_name=?
emp_id=#{emp_id} and emp_name=#{emp_name}
select * from employee where emp_id=? and emp_name=?
一般都是使用#{};安全;在不支持预编译参数的位置要进行取值就使用${};
-->
<!-- public List<Employee> getAllEmps(); -->
<!-- resultType="":如果返回的是集合,写的是集合里面元素的类型 -->
<select id="getAllEmps" resultType="com.lql.bean.Employee">
select * from employee
</select>
<!-- 查询返回一个map -->
<!-- public Map<String, Object> getEmpByIdReturnMap(Integer emp_id); -->
<select id="getEmpByIdReturnMap" resultType="map">
select * from employee where emp_id=#{emp_id}
</select>
<!-- 查询多个返回一个map;查询多个情况下,集合里面写元素类型 -->
<!-- public Map<Integer, Employee> getAllEmpsReturnMap(); -->
<select id="getAllEmpsReturnMap" resultType="com.lql.bean.Employee">
select * from employee
</select>
</mapper>
&&&&&&&&&&&&&&&&&&&&&&& KeyDao.xml &&&&&&&&&&&&&&&&&
<?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">
<mapper namespace="com.lql.dao.KeyDao">
<!-- public List<Key> getKeysByLockId(Integer id);
按照锁id查出所有的key
-->
<select id="getKeysByLockId" resultType="com.lql.bean.Key">
SELECT * FROM t_key WHERE lockid = #{id};
</select>
<!-- public Key getKeyByIdSimple(Integer id); -->
<!-- 查询key的时候也可以带上锁信息 -->
<!-- id keyname lockid -->
<!--
private Integer id;//钥匙的id
private String keyName;//钥匙名
private Lock lock;//当前钥匙能开哪个锁
-->
<select id="getKeyByIdSimple" resultMap="mykey02">
select * from t_key where id = #{id}
</select>
<resultMap type="com.lql.bean.Key" id="mykey02">
<id property="id" column="id"/>
<result property="keyName" column="keyname"/>
<!-- 告诉mybatis自己去调用一个查询查锁
select="":指定一个查询sql的唯一标识;
mybatis自动调用指定的sql将查出的lock封装进来
public Lock getLockByIdSimple(Integer id);需要传入锁id
告诉mybatis把那一列的值传过去:
column="":指定将哪一列的数据传递过去
-->
<association property="lock" select="com.lql.dao.LockDao.getLockByIdSimple"
column="lockid" fetchType="lazy"></association>
</resultMap>
<!-- getKeyById(Integer) -->
<select id="getKeyById" resultMap="mykey">
SELECT k.id,k.keyname,k.lockid,l.id lid,l.lockname
FROM t_key k LEFT JOIN t_lock l ON k.lockid = l.id
WHERE k.id = #{id};
</select>
<!-- 自定义封装规则:使用级联属性封装 联合查询出来的结果-->
<!-- <resultMap type="com.lql.bean.Key" id="mykey">
<id property="id" column="id"/>
<result property="keyName" column="keyname"/>
<result property="lock.id" column="lid"/>
<result property="lock.lockName" column="lockname"/>
</resultMap> -->
<!-- mybatis推荐的 -->
<resultMap type="com.lql.bean.Key" id="mykey">
<id property="id" column="id"/>
<result property="keyName" column="keyname"/>
<!-- 接下来的属性是一个对象,自定义这个对象的封装规则;
使用association:表示联合了一个对象
javaType="":指定这个属性的类型
-->
<association property="lock" javaType="com.lql.bean.Lock">
<!-- 定义lock属性对应的这个Lock对象如何封装 -->
<id property="id" column="lid"/>
<result property="lockName" column="lockname"/>
</association>
</resultMap>
</mapper>
&&&&&&&&&&&&&&&&&&&&&&& LockDao.xml &&&&&&&&&&&&&&&&&
<?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">
<mapper namespace="com.lql.dao.LockDao">
<!-- public Lock getLockByIdByStep(Integer id); -->
<select id="getLockByIdByStep" resultMap="mylockstep">
select * from t_lock where id=#{id}
</select>
<!-- collection分步查询 -->
<resultMap type="com.lql.bean.Lock" id="mylockstep">
<id property="id" column="id"/>
<result property="lockName" column="lockname"/>
<!-- collection指定集合类型的属性封装规则 -->
<collection property="keys"
select="com.lql.dao.KeyDao.getKeysByLockId"
column="{id=id}"></collection>
<!-- {key1=列名,key2=列名} -->
</resultMap>
<!-- public Lock getLockByIdSimple(Integer id); -->
<select id="getLockByIdSimple" resultType="com.lql.bean.Lock">
select * from t_lock where id=#{id}
</select>
<!-- public Lock getLockById(Integer id); -->
<select id="getLockById" resultMap="mylock">
SELECT l.*,k.id kid,k.keyname,k.lockid
FROM t_lock l LEFT JOIN t_key k
ON l.id=k.lockid WHERE l.id = #{id}
</select>
<!--
private Integer id;
private String lockName;
//查锁的时候把所有的钥匙也查出来
private List<Key> keys;
id lockname kid keyname lockid
3 303办公室的锁 3 303钥匙1 3
3 303办公室的锁 4 303钥匙2 3
3 303办公室的锁 5 303钥匙3 3
-->
<resultMap type="com.lql.bean.Lock" id="mylock">
<id property="id" column="id"/>
<result property="lockName" column="lockname"/>
<!--
collection:定义集合元素的封装
property="":指定哪个属性是集合属性
javaType:指定对象类型(association)
ofType:指定集合里面元素的类型
-->
<collection property="keys" ofType="com.lql.bean.Key">
<!-- 标签体中集合中这个元素的封装规则 -->
<id property="id" column="kid"/>
<result property="keyName" column="keyname"/>
</collection>
</resultMap>
</mapper>
5.mybatis-config.xml
<?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">
<configuration>
<settings>
<!-- 开启延迟加载开关 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 开启属性按需加载(默认开启) -->
<!-- <setting name="aggressiveLazyLoading" value="false"/> -->
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="com.lql.dao"/>
</mappers>
</configuration>
6、MyBatisTest.java
package com.lql.test;
import static org.junit.Assert.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
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 org.junit.Before;
import org.junit.Test;
import com.lql.bean.Cat;
import com.lql.bean.Employee;
import com.lql.bean.Key;
import com.lql.bean.Lock;
import com.lql.dao.CatDao;
import com.lql.dao.EmployeeDao;
import com.lql.dao.KeyDao;
import com.lql.dao.LockDao;
public class MyBatisTest {
//工厂一个
SqlSessionFactory sqlSessionFactory;
@Before
public void initSqlSessionFactory() throws IOException{
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void test() {
SqlSession openSession = sqlSessionFactory.openSession();
try {
EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class);
Employee empById = employeeDao.getEmpById(1);
System.out.println(empById);
} finally {
openSession.close();
}
}
@Test
public void test02() {
SqlSession openSession = sqlSessionFactory.openSession();
try {
EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class);
/*Employee employee = new Employee(null, "haha", 0, "aaa");
int i = employeeDao.insertEmployee(employee);
System.out.println("--->"+i);
System.out.println("刚才插入的id:"+employee.getEmp_id());*/
Employee employee = new Employee(null, "haha", 0, "aaa");
employeeDao.insertEmployee2(employee);
System.out.println(employee.getEmp_id());
openSession.commit();
} finally {
openSession.close();
}
}
@Test
public void test03() {
SqlSession openSession = sqlSessionFactory.openSession();
try {
EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class);
/*Employee empByIdAndEmpName = employeeDao.getEmpByIdAndEmpName(1, "admin");
System.out.println(empByIdAndEmpName);
Employee empById = employeeDao.getEmpById(1);
System.out.println(empById);*/
Map<String, Object> map = new HashMap<String,Object>();
map.put("emp_id", 1);
map.put("emp_name", "admin");
map.put("tableName", "employee");
Employee empByIdAndEmpName2 = employeeDao.getEmpByIdAndEmpName1(map);
System.out.println(empByIdAndEmpName2);
} finally {
openSession.close();
}
}
@Test
public void test04() {
SqlSession openSession = sqlSessionFactory.openSession();
try {
EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class);
//查询多条记录封装list
/*List<Employee> allEmps = employeeDao.getAllEmps();
for (Employee employee : allEmps) {
System.out.println(employee);
}*/
//查询单条记录封装map
/*Map<String, Object> map = employeeDao.getEmpByIdReturnMap(1);
System.out.println(map);*/
//查询多条记录封装map
Map<Integer, Employee> map = employeeDao.getAllEmpsReturnMap();
System.out.println(map);
Employee employee = map.get(1);
System.out.println(employee.getEmp_name());
} finally {
openSession.close();
}
}
/**
* 默认mybatis自动封装结果集;
* 1)、按照列名和属性名一一对应的规则(不区分大小写);
* 2)、如果不一一对应:
* 1)、开启驼峰命名法(满足驼峰命名规则 aaa_bbb aaaBbb)
* 2)、起别名
*/
@Test
public void test05() {
SqlSession openSession = sqlSessionFactory.openSession();
try {
CatDao mapper = openSession.getMapper(CatDao.class);
Cat catById = mapper.getCatById(2);
System.out.println(catById);
} finally {
openSession.close();
}
}
/**
* 联合查询情况下
* 1、使用级联属性封装联合查询后的所有结果
*/
@Test
public void test06() {
SqlSession openSession = sqlSessionFactory.openSession();
try {
KeyDao mapper = openSession.getMapper(KeyDao.class);
Key keyById = mapper.getKeyById(2);
System.out.println(keyById);
} finally {
openSession.close();
}
}
@Test
public void test07() {
SqlSession openSession = sqlSessionFactory.openSession();
try {
LockDao mapper = openSession.getMapper(LockDao.class);
Lock lockById = mapper.getLockById(3);
System.out.println(lockById);
System.out.println("所有🔑如下:");
List<Key> keys = lockById.getKeys();
for (Key key : keys) {
System.out.println(key);
}
} finally {
openSession.close();
}
}
@Test
public void test08() {
SqlSession openSession = sqlSessionFactory.openSession();
try {
LockDao mapper = openSession.getMapper(LockDao.class);
Lock lockById = mapper.getLockById(3);
System.out.println(lockById);
System.out.println("所有🔑如下:");
List<Key> keys = lockById.getKeys();
for (Key key : keys) {
System.out.println(key);
}
} finally {
openSession.close();
}
}
/**
* 分步查询
* 查询🔑的时候顺便查出🔒
* 1)、Key key = keyDao.getKeyById(1);
* 2)、Lock lock = lockDao.getLockById(1);
* @throws InterruptedException
*/
@Test
public void test09() throws InterruptedException {
SqlSession openSession = sqlSessionFactory.openSession();
try {
KeyDao mapper = openSession.getMapper(KeyDao.class);
Key keyByIdSimple = mapper.getKeyByIdSimple(1);
//严重性能;
System.out.println(keyByIdSimple.getKeyName());
//按需加载(需要的时候再去查询)全局开启按需加载策略
//延迟加载,不着急加载(查询对象)
Thread.sleep(3000);
String lockName = keyByIdSimple.getLock().getLockName();
System.out.println(lockName);
} finally {
openSession.close();
}
}
/**
* 一般我们在工作的时候:写成两个方法
* public Key getKeySimple(Integer id);
*
* 推荐都来写连接查询
* public Key getKeyAssicate()
* @throws InterruptedException
*/
@Test
public void test10() throws InterruptedException {
SqlSession openSession = sqlSessionFactory.openSession();
try {
LockDao mapper = openSession.getMapper(LockDao.class);
Lock lockByIdByStep = mapper.getLockByIdByStep(3);
System.out.println(lockByIdByStep.getLockName());
List<Key> keys = lockByIdByStep.getKeys();
for (Key key : keys) {
System.out.println(key.getKeyName());
}
} finally {
openSession.close();
}
}
}
五、动态sql
1、总体架构:

2、bean
package com.lql.bean;
import java.util.Date;
public class Teacher {
private Integer id;
private String name;
private String course;
private String address;
private Date birth;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCourse() {
return course;
}
public void setCourse(String course) {
this.course = course;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
@Override
public String toString() {
return "Teacher [id=" + id + ", name=" + name + ", course=" + course + ", address=" + address + ", birth="
+ birth + "]";
}
}
3、dao
package com.lql.dao;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.lql.bean.Teacher;
public interface TeacherDao {
public Teacher getTeacherById(Integer id);
public List<Teacher> getTeacherByCondition(Teacher teacher);
public List<Teacher> getTeacherByIdIn(@Param("ids")List<Integer> ids);
public List<Teacher> getTeacherByConditionChoose(Teacher teacher);
public int updateTeacher(Teacher teacher);
}
4、dao.xml
<?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">
<mapper namespace="com.lql.dao.TeacherDao">
<resultMap type="com.lql.bean.Teacher" id="teacherMap">
<id property="id" column="id"/>
<result property="address" column="address"/>
<result property="birth" column="birth_date"/>
<result property="course" column="class_name"/>
<result property="name" column="t_name"/>
</resultMap>
<!-- 抽取可重用的sql语句 -->
<sql id="selectSql">select * from t_teacher</sql>
<!-- id t_name class_name address birth_date -->
<!-- public Teacher getTeacherById(Integer id); -->
<select id="getTeacherById" resultMap="teacherMap">
<include refid="selectSql"></include>
<!-- select * from t_teacher --> where id=#{id}
</select>
<!-- public List<Teacher> getTeacherByCondition(Teacher teacher); -->
<select id="getTeacherByCondition" resultMap="teacherMap">
select * from t_teacher
<!-- test="":编写判断条件
id!=null:取出传入的javaBean属性中的id值,判断其是否为空
-->
<!-- <where>标签可以帮我们去除掉前面的and -->
<!-- <trim>标签截取字符串
prefix="":前缀;为我们下面的sql整体添加一个前缀;
prefixOverrides="":去除整体字符串前面多余的字符;
suffix="":为整体添加一个后缀
suffixOverrides="":后面哪个多了,可以去掉
-->
<!-- 我们的查询条件就放在where标签中,每个and写在前面,where帮我们自动取出前面多余的and -->
<trim prefix="where"
suffixOverrides="and ">
<if test="id!=null">
id > #{id} and
</if>
<!-- 空串""
and:&&
or:||;
if():传入非常强大的判断条件;
OGNL表达式:对象导航图(相当于级联属性)
方法、静态方法、构造器、xxx
在mybatis中,传入的参数可以用来做判断;
额外还有两个东西:
_parameter:代表传入来的参数:
1)、传入了单个参数:_parameter就代表这个参数
2)、传入了多个参数:_parameter就代表多个参数集合起来的map
_databaseId:代表当前环境
如果配置了databaseIdProvider,_parameter就有值
-->
<!-- 绑定一个表达式的值到一个变量(不推荐) -->
<bind name="_name" value="'%'+name+'%'"/>
<if test="name!=null && !name.equals("")">
t_name like #{_name} and
</if>
<if test="birth!=null">
birth_date < #{birth} and
</if>
</trim>
</select>
<!-- public List<Teacher> getTeacherByIdIn(List<Integer> ids); -->
<select id="getTeacherByIdIn" resultMap="teacherMap">
SELECT * FROM t_teacher WHERE id IN
<!-- 帮我们遍历集合的;
collection="":指定要遍历的集合的key
close="" :以什么结束
index="i" :索引
如果遍历的是一个list:
index:指定的变量保存了当前索引;
item:就是保存当前遍历的元素的值;
如果遍历的是一个map:
index:指定的变量就是保存了当前遍历的元素的key
item:就是保存当前遍历的元素的值;
item="变量名" :每次遍历出的元素起一个变量名方便引用
open="" :以什么开始
separator="":每次遍历元素的分隔符
-->
<if test="ids.size >0">
<foreach collection="ids" item="id_item"
open="(" close=")" separator=",">
#{id_item}
</foreach>
</if>
</select>
<!-- public List<Teacher> getTeacherByConditionChoose(Teacher teacher); -->
<select id="getTeacherByConditionChoose" resultMap="teacherMap">
SELECT * FROM t_teacher
<where>
<choose>
<when test="id!=null">
id=#{id}
</when>
<when test="name!=null and !name.equals("")">
t_name=#{name}
</when>
<when test="birth!=null">
birth_date=#{birth}
</when>
<otherwise>
1=1
</otherwise>
</choose>
</where>
</select>
<!-- public int updateTeacher(Teacher teacher); -->
<update id="updateTeacher">
UPDATE t_teacher
<set>
<if test="name!=null and !name.equals("")">
t_name=#{name},
</if>
<if test="course!=null and !course.equals("")">
class_name=#{course},
</if>
<if test="address!=null and !address.equals("")">
address=#{address},
</if>
<if test="birth!=null">
birth_date=#{birth}
</if>
</set>
<where>
id=#{id}
</where>
</update>
</mapper>
5、mybatis-config.xml
<?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">
<configuration>
<settings>
<!-- 开启延迟加载开关 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 开启属性按需加载(默认开启) -->
<!-- <setting name="aggressiveLazyLoading" value="false"/> -->
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="com.lql.dao"/>
</mappers>
</configuration>
6、MyBatisTest.java
package com.lql.test;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
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 org.junit.Before;
import org.junit.Test;
import com.lql.bean.Teacher;
import com.lql.dao.TeacherDao;
public class MyBatisTest {
//工厂一个
SqlSessionFactory sqlSessionFactory;
@Before
public void initSqlSessionFactory() throws IOException{
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void test() {
SqlSession openSession = sqlSessionFactory.openSession();
try {
TeacherDao mapper = openSession.getMapper(TeacherDao.class);
/*Teacher teacher = new Teacher();
teacher.setId(1);
teacher.setName("%a%");
//teacher.setBirth(new Date());
List<Teacher> list = mapper.getTeacherByCondition(teacher);*/
//List<Teacher> list = mapper.getTeacherByIdIn(Arrays.asList(1,2,3,4,5));
Teacher teacher = new Teacher();
//teacher.setId(1);
//teacher.setName("%a%");
List<Teacher> list = mapper.getTeacherByConditionChoose(teacher);
System.out.println(list);
} finally {
openSession.close();
}
}
@Test
public void test02() {
SqlSession openSession = sqlSessionFactory.openSession();
try {
TeacherDao mapper = openSession.getMapper(TeacherDao.class);
Teacher teacher = new Teacher();
teacher.setId(1);
teacher.setName("hahaha");
int i = mapper.updateTeacher(teacher);
System.out.println(i);
openSession.commit();
} finally {
openSession.close();
}
}
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("java");
list.add("c++");
list.add("python");
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
六、缓存机制
1、缓存作用
- 暂时的存储一些数据
- 加快系统的查询速度
2、MyBatis缓存机制
-
Map保存查询出的一些数据
-
- 线程级别的缓存
- 本地缓存
- SqlSession级别的缓存
- 默认存在
-
- 全局范围的缓存
- namespace级别的缓存
- 除过当前的线程/SqlSession能用外其他也可以使用
3、一级缓存
- 只要之前查询过的数据,mybatis就会保存在一个缓存中(Map)
- 下次获取直接从缓存中拿
一级缓存失效的几种情况
- 不同的SqlSession对应不同的一级缓存
- 同一个SqlSession但是查询条件不同
- 同一个SqlSession两次查询期间执行了任何一次增删改操作
- 同一个SqlSession两次查询期间手动清空了缓存
源码位置
- key很长(敏感)

4、二级缓存
- Sqlsession关闭或者提交以后,一级缓存的数据会放在二级缓存中
- mybatis默认没有使用的
1.二级缓存的使用
1、全局配置开启二级缓存
<!-- 开启全局缓存开关(默认开启) -->
<setting name="cacheEnabled" value="true"/>
2、配置某个dao.xml文件,让其使用二级缓存
<!-- 使用二级缓存 -->
<cache/>
2.缓存原理

5、缓存有关设置
1.全局setting的cacheEnable
- –配置二级缓存的开关(一级缓存一直是打开的)
2.select标签的useCache属性
- –配置这个select是否使用二级缓存(一级缓存一直是使用的)
3.sql标签的flushCache属性
- –sql执行以后,会同时清空一级和二级缓存
- 增删改默认flushCache=true
- 查询默认flushCache=false
4.sqlSession.clearCache()
- –只是用来清除一级缓存
- 当在某一个作用域 (一级缓存Session/二级缓存Namespaces) 进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear
6、整合第三方缓存
- MyBatis—–Cache接口
- 整合ehcache(非常专业的java进程内的缓存框架)
1.导包
ehcache-core-2.6.11.jar(ehcache核心包) mybatis-ehcache-1.2.1.jar(ehcache的整合包)
slf4j-api-1.7.30.jar slf4j-log4j12-1.7.30.jar
2.ehcache配置文件
- 文件名叫ehcache.xml
- 放在类路径的根目录下(conf下)
3.在mapper.xml中配置使用自定义的缓存
<!-- 使用mybatis默认二级缓存<cache /> -->
<cache type="org.mybatis.caches.ehcache.EhcacheCache" />
4.别的dao还要用这个缓存
<!-- 和别的dao共用一块缓存 -->
<cache-ref namespace="com.lql.dao.TeacherDao"/>
5.echcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<!-- 磁盘保存路径 -->
<diskStore path="D:\44\ehcache" />
<defaultCache
maxElementsInMemory="1"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
<!--
属性说明:
l diskStore:指定数据在磁盘中的存储位置。
l defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略
以下属性是必须的:
l maxElementsInMemory - 在内存中缓存的element的最大数目
l maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
l eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
l overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
以下属性是可选的:
l timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大
l timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
l diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
l diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作
l memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)
-->
6.MyBatisTest.java
package com.lql.test;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
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 org.junit.Before;
import org.junit.Test;
import com.lql.bean.Teacher;
import com.lql.dao.TeacherDao;
public class MyBatisTest {
//工厂一个
SqlSessionFactory sqlSessionFactory;
@Before
public void initSqlSessionFactory() throws IOException{
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
/**
* 体会一级缓存
*/
@Test
public void test() {
SqlSession openSession = sqlSessionFactory.openSession();
try {
TeacherDao mapper = openSession.getMapper(TeacherDao.class);
Teacher teacherById = mapper.getTeacherById(1);
System.out.println(teacherById);
System.out.println("=========================");
Teacher teacherById2 = mapper.getTeacherById(1);
System.out.println(teacherById2);
System.out.println(teacherById == teacherById2);
} finally {
openSession.close();
}
}
/**
* 一级缓存失效的几种情况
* 一级缓存是SqlSession级别的缓存;
* 1、不同的sqlSession使用不同的一级缓存;
* 只有在同一个sqlSession期间查询到的数据会保存在这个sqlSession的缓存中;
* 下次使用个这个sqlSession查询会从缓存中拿。
* 2、同一个方法,不同的参数,由于可能之前没查过,所以还会发新的sql;
* 3、在这个sqlSession期间执行任何一次增删改操作,会把缓存清空;
* 4、手动清空了缓存;
*
* 每次查询,先看一级缓存中有没有,如果没有就去发送新的sql;每个sqlSession拥有自己的一级缓存;
*
*/
@Test
public void test02() {
SqlSession openSession = sqlSessionFactory.openSession();
//1、第一个会话
TeacherDao mapper = openSession.getMapper(TeacherDao.class);
Teacher teacher1 = mapper.getTeacherById(1);
System.out.println(teacher1);
System.out.println("============================");
//执行任何一个增删改操作
/*Teacher teacher = new Teacher();
teacher.setId(3);
teacher.setName("3333");
mapper.updateTeacher(teacher);*/
System.out.println("手动清空缓存");
//清空当前sqlSession的以及缓存
//openSession.clearCache();
System.out.println("============================");
Teacher teacher2 = mapper.getTeacherById(1);
System.out.println(teacher2);
//2、第二个会话
/*SqlSession openSession2 = sqlSessionFactory.openSession();
TeacherDao mapper2 = openSession2.getMapper(TeacherDao.class);
Teacher teacher2 = mapper2.getTeacherById(1);
System.out.println(teacher2);*/
openSession.commit();
openSession.close();
//openSession2.close();
}
/**
* 体验二级缓存
*/
@Test
public void test03() {
SqlSession openSession = sqlSessionFactory.openSession();
SqlSession openSession2 = sqlSessionFactory.openSession();
TeacherDao mapper1 = openSession.getMapper(TeacherDao.class);
TeacherDao mapper2 = openSession2.getMapper(TeacherDao.class);
//1、第一个dao查询1号teacher
Teacher teacher1 = mapper1.getTeacherById(1);
System.out.println(teacher1);
openSession.close();
//1、第二个dao查询1号teacher
Teacher teacher2 = mapper2.getTeacherById(1);
System.out.println(teacher2);
openSession.close();
}
/**
*
* 1、不会出现一级缓存和二级缓存中有同一个数据:
* 二级缓存中,一级缓存关闭了就有了;
* 一级缓存中,二级缓存中没有此数据,就会看一级缓存,一级缓存没有就去查询数据库
* 2、任何时候都是先看二级缓存,再看一级缓存,如果大家都没有就去查询数据库;
* 二-----》一====》库
*/
@Test
public void test04() {
SqlSession openSession = sqlSessionFactory.openSession();
TeacherDao teacherDao = openSession.getMapper(TeacherDao.class);
Teacher teacher = teacherDao.getTeacherById(1);
System.out.println(teacher);
openSession.close();
System.out.println("===============");
SqlSession openSession2 = sqlSessionFactory.openSession();
TeacherDao teacherDao2 = openSession2.getMapper(TeacherDao.class);
Teacher teacherById = teacherDao2.getTeacherById(1);
System.out.println(teacherById);
Teacher teacherById2 = teacherDao2.getTeacherById(1);
System.out.println(teacherById2);
/*Teacher teacherById2 = teacherDao2.getTeacherById(1);
System.out.println(teacherById2);
System.out.println("以下是查询二号teacher:");
Teacher teacherById3 = teacherDao2.getTeacherById(2);
System.out.println(teacherById3);
Teacher teacherById4 = teacherDao2.getTeacherById(2);
System.out.println(teacherById4);
*/
openSession2.close();
}
}
七、SSM整合
- SSM
- Spring+SpringMVC+MyBatis
1、导包
1.Spring
【aop核心】
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aspects-5.2.9.RELEASE.jar
【ioc核心】
commons-logging-1.1.3.jar
spring-aop-5.2.9.RELEASE.jar
spring-beans-5.2.9.RELEASE.jar
spring-context-5.2.9.RELEASE.jar
spring-core-5.2.9.RELEASE.jar
spring-expression-5.2.9.RELEASE.jar
【jdbc核心】
spring-jdbc-5.2.9.RELEASE.jar
spring-orm-5.2.9.RELEASE.jar
spring-tx-5.2.9.RELEASE.jar
【测试】
spring-test-5.2.9.RELEASE.jar
2.SpringMVC
【Ajax】
jackson-annotations-2.12.0.jar
jackson-core-2.12.0.jar
jackson-databind-2.12.0.jar
【数据校验】
hibernate-validator-6.1.7.Final.jar
hibernate-validator-annotation-processor-6.1.7.Final.jar
classmate-1.5.1.jar
jboss-logging-3.4.1.Final.jar
validation-api-2.0.1.Final.jar
【上传下载】
commons-fileupload-1.4.jar
commons-io-2.8.0.jar
【jstl-jsp标准标签库】
jstl.jar
standard.jar
【验证码】
kaptcha-2.3.2.jar
【SpringMVC核心】
spring-web-5.2.9.RELEASE.jar
spring-webmvc-5.2.9.RELEASE.jar
3.MyBatis
【mybatis核心】
mybatis-3.5.6.jar
【和spring的整合包】
mybatis-spring-2.0.6.jar
【ehcache整合】
ehcache-core-2.6.11.jar
mybatis-ehcache-1.2.1.jar
log4j-1.2.17.jar
slf4j-api-1.7.30.jar
slf4j-log4j12-1.7.30.jar
4.其他的
//数据源,驱动
mysql-connector-java-8.0.22.jar
c3p0-0.9.5.5.jar
mchange-commons-java-0.2.20.jar
//分页插件
pagehelper-5.2.0.jar
jsqlparser-3.2.jar
5.总览:

2、写配置
0.web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>7.SSM</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 配置Spring容器启动 -->
<!-- needed for ContextLoaderListener -->
<context-param>
<param-name>contextConfigLocation</param-name>
<!-- 指定Spring配置文件位置 -->
<param-value>classpath:spring/applicationContext.xml</param-value>
</context-param>
<!-- Bootstraps the root web application context before servlet initialization -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 配置springmvc的前端控制器 -->
<!-- The front controller of this Spring Web application, responsible for handling all application requests -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map all requests to the DispatcherServlet for handling -->
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 两个标准配置 -->
<!-- 字符编码 -->
<!-- <filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> -->
<!-- 支持Rest风格的过滤器 -->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
1.spring的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!-- Spring除过控制器不要,剩下的业务逻辑组件都要(包括dao,service。。) -->
<context:component-scan base-package="com.lql">
<!-- 扫描排除不写use-default-filters="false" -->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 0、导入外部配置文件 -->
<context:property-placeholder location="classpath:dbconfig.properties"/>
<!-- 1、配数据源 -->
<bean id="ds" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="maxPoolSize" value="${jdbc.maxPoolSize}"></property>
<property name="minPoolSize" value="${jdbc.minPoolSize}"></property>
</bean>
<!-- 2、配置JdbcTemplate操作数据库(pass) -->
<!-- 3、配置使用mybatis操作数据库 -->
<!-- 可以根据配置文件得到SqlSessionFactory -->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="ds"></property>
<!-- 指定xml映射文件的位置 -->
<property name="mapperLocations" value="classpath:mybatis/mapper/*.xml"></property>
<!-- 指定配置文件位置 -->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property>
</bean>
<!-- 我们要把每一个dao接口的实现加入到ioc容器 -->
<!-- <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
指定dao接口所在的包
<property name="basePackage" value="com.lql.dao"></property>
</bean> -->
<!-- 替换上面的简单写法 -->
<mybatis-spring:scan base-package="com.lql.dao"/>
<!-- 4、配置事务控制(配置事务管理器,让他控制住数据源里面的连接的关闭和提交) -->
<bean id="tm" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="ds"></property>
</bean>
<!-- 5、基于xml配置,配置事务(哪些方法切入事务,还要写切入点表达式) -->
<aop:config>
<!-- 配置切入点表达式 -->
<aop:pointcut expression="execution(* com.lql.service.*.*(..))" id="txPoint"/>
<aop:advisor advice-ref="myTx" pointcut-ref="txPoint"/>
</aop:config>
<!-- 6、配置事务增强、事务属性、事务建议
transaction-manager="tm":指定要配置的事务管理器的id
-->
<tx:advice id="myTx" transaction-manager="tm">
<!-- 配置事务属性 -->
<tx:attributes>
<tx:method name="*" rollback-for="java.lang.Exception"/>
<tx:method name="get*" read-only="true"/>
<!-- <tx:method name="insertEmp" isolation="READ_UNCOMMITTED"/> -->
</tx:attributes>
</tx:advice>
</beans>
2.springmvc的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- SpringMVC只扫描控制器;禁用默认的规则 -->
<context:component-scan base-package="com.lql" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 配置文件上传解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8"></property>
<property name="maxUploadSize" value="#{1024*1024*20}"></property>
</bean>
<!-- 扫描静态资源 -->
<mvc:default-servlet-handler/>
<!-- 扫描动态资源 -->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
3.mybatis的配置
<!-- 2、配置JdbcTemplate操作数据库(pass) -->
<!-- 3、配置使用mybatis操作数据库 -->
<!-- 可以根据配置文件得到SqlSessionFactory -->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 指定配置文件位置 -->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"></property>
<property name="dataSource" ref="ds"></property>
<!-- 指定xml映射文件的位置 -->
<property name="mapperLocations" value="classpath:mybatis/mapper/*.xml"></property>
</bean>
<!-- 我们要把每一个dao接口的实现加入到ioc容器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 指定dao接口所在的包 -->
<property name="basePackage" value="com.lql.dao"></property>
</bean>
mybatis-config.xml
<?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">
<configuration>
<settings>
<!-- 开启延迟加载开关 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 开启属性按需加载(默认开启) -->
<!-- <setting name="aggressiveLazyLoading" value="false"/> -->
<!-- 开启全局缓存开关(默认开启) -->
<setting name="cacheEnabled" value="true"/>
</settings>
<!-- 配置分页插件 -->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
</configuration>
3、测试(分页功能)
1.controller
package com.lql.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.lql.bean.Teacher;
import com.lql.service.TeacherService;
@Controller
public class TeacherController {
@Autowired
TeacherService teacherService;
@RequestMapping("/getTea")
public String getTeacher(@RequestParam(value="id",defaultValue="1")Integer id,Model model){
Teacher t = teacherService.getTeacher(id);
model.addAttribute("teacher", t);
return "success";
}
@RequestMapping("/getAll")
public String getAll(@RequestParam(value="pn",defaultValue="1")Integer pn,Model model){
//紧跟他的查询就是一个分页查询
PageHelper.startPage(pn, 5);
List<Teacher> list = teacherService.getAll();
//将查询的结果放在pageinfo中这个pageInfo就有非常多能够用的
//第二份传入连续要显示的页码
PageInfo<Teacher> pageInfo = new PageInfo<>(list,6);
System.out.println("当前页码:"+pageInfo.getPageNum());
System.out.println("总页码:"+pageInfo.getPages());
System.out.println("总记录数:"+pageInfo.getTotal());
System.out.println("当前页有几条记录:"+pageInfo.getSize());
System.out.println("当前页的pageSize:"+pageInfo.getPageSize());
System.out.println("前一页:"+pageInfo.getPrePage());
System.out.println("结果:"+pageInfo.getList());//查询结果
int[] nums = pageInfo.getNavigatepageNums();
System.out.println(nums);
model.addAttribute("pageInfo",pageInfo);
return "success";
}
}
2.success.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>成功!</h1>
${teacher }
<table cellpadding="5" cellspacing="0" border="1">
<tr>
<th>id</th>
<th>name</th>
<th>course</th>
<th>address</th>
</tr>
<c:forEach items="${pageInfo.list}" var="tea">
<tr>
<td>${tea.id}</td>
<td>${tea.name}</td>
<td>${tea.course}</td>
<td>新城区</td>
</tr>
</c:forEach>
<tr>
<td colspan="4">
<a href="getAll?pn=1">首页</a><a href="getAll?pn=${pageInfo.prePage }">上一页</a>
<c:forEach items="${pageInfo.navigatepageNums}" var="num">
<c:if test="${num == pageInfo.pageNum}">
【${num}】
</c:if>
<c:if test="${num != pageInfo.pageNum}">
<a href="getAll?pn=${num}">${num}</a>
</c:if>
</c:forEach>
<a href="getAll?pn=${pageInfo.nextPage}">下一页</a><a href="getAll?pn=${pageInfo.pages}">末页</a>
</td>
</tr>
</table>
</body>
</html>
4、工程结构:

八、MBG
- MyBatis Generator(代码生成器)
- MyBatis官方提供
- 帮我们逆向生成
1、正向
- table—》JavaBean—-》BookDao—-》dao.xml—-》xxx
2、逆向工程
- 根据数据表table,逆向分析数据表,自动生成 JavaBean—-》BookDao—-》dao.xml—-》xxx
3、配置步骤
1.导包
- mbg的核心包
mybatis-generator-core-1.4.0.jar
2.配置
- 新建xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- MyBatis3Simple:简单版 -->
<context id="DB2Tables" targetRuntime="MyBatis3">
<!-- jdbcConnection:指导连接到哪个数据库 -->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/test?serverTimezone=UTC"
userId="root"
password="123456">
</jdbcConnection>
<javaTypeResolver >
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- javaModelGenerator:生成pojo
targetPackage:生成的pojo放在哪个包
targetProject:放在哪个工程下
-->
<javaModelGenerator targetPackage="com.lql.bean" targetProject=".\src">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- sqlMapGenerator:sql映射文件生成器(指定xml生成的地方) -->
<sqlMapGenerator targetPackage="com.lql.dao" targetProject=".\conf">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!-- javaClientGenerator:生成dao接口 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.lql.dao" targetProject=".\src">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!-- table:指定要逆向生成哪个数据表
tableName="t_cat":表名
domainObjectName="Cat":这个表对应的对象名
-->
<table tableName="t_cat" domainObjectName="Cat" ></table>
<table tableName="employee" domainObjectName="Employee" ></table>
<table tableName="t_teacher" domainObjectName="Teacher" ></table>
</context>
</generatorConfiguration>
3.mbg生成代码
package com.lql.test;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;
public class MBGTest {
public static void main(String[] args) throws Exception {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("mbg.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
//代码生成
myBatisGenerator.generate(null);
System.out.println("生成🆗了!");
}
}