目录
3.5 SQL Mapper映射文件中的namespace作用
6.1 创建java web项目,引入依赖,配置Tomcat启动、核心xml文件,映射xml文件。
10.3返回结果没有合适的实体类,这时候我们可以指定Map集合接收
10.4 结果集映射(指定使用结果集映射,将数据库字段名和Java类属性一一对应)
第三种:分步查询(这种方法常用,优点一可复用,优点二支持懒加载)
⼆级缓存的失效:只要两次查询之间出现了增删改操作。⼆级缓存就会失效。【⼀级缓存也会失效】
14.2QBC(Query By Criteria)查询风格。
16.1 @Insert @Delete @Update @Select注解
第一章:MyBatis概述
1.1 框架
1.2 三层架构
*表现层:直接跟前端打交互(一是接收前端ajax请求,二是返回json数据给前端)
*业务逻辑层:一是处理表现层转发过来的前端请求(也就是具体业务),二是将从持久层获取的数据返回到表现层。
*数据访问层:直接操作数据库完成CRUD,并将获得到的数据返回给上一层(也就是业务逻辑层)。
java持久层框架:MyBatis、Hibernate、JOOQ、Guzz、Spring Data、AvticeJDBC......等
1.3 JDBC不足
1、sql语句写死在java程序中
2、JDBC代码比较繁琐,给sql语句填入值需要重复的set。
3、获取结果集需要遍历结果集,重复的new对象,重复的get数据库返回的数据,再重复的set数据给对象。
1.4 了解MyBatis
1、MyBatis是对jdbc的封装,通过MyBatis完成CRUD
2、MyBatis之前叫做ibatis,后来改名MyBatis
3、MyBatis是持久层框架
mybatis中文文档地址:https://mybatis.net.cn
*ORM:对象关系映射
O(Object):Java虚拟机中的Java对象
R(Relational):关系型数据库
M(Mapping):将Java虚拟机中的Java对象映射到数据库表中一行记录,或是将数据库中一行记录映射成Java虚拟机中的Java对象。
第二章:MyBatis入门程序
*创建数据表:并且插入测试数据
2.1 开发第一个MyBatis程序:
1、resources目录:放在这个目录当中的,一般都是资源文件,配置文件。直接放在目录下的资源,等同于放在类的根路径下。
2、开发步骤:
*第一步:打包方式 jar
*第二步:引入依赖
- mybatis依赖
- mysql驱动依赖
*第三步:编写mybatis核心配置文件,mybatis-config.xml
注意:这个文件名不是固定的,可以使用其他名字,只是大部分人都使用这个名字。
这个文件存放的位置也不是固定的,可以随意,但是一般情况下,会放到类的根路径下。
*第四步:编写XxxxMapper.xml文件,在这个配置文件当中编写SQL语句,这个文件名不是固定的,放的位置也不是固定的,叫做CarMapper.xml,暂时放在reources目录下。
*第五步:在mybatis-config.xml文件中指定XxxxMapper.xml文件所在的路径。
*第六步:编写Mybatis程序,使用mybatis的类库,编写mybatis程序,连接数据库,做CRUD操作即可。
在Mybatis中,负责执行SQL语句的对象叫做什么呢?:SqlSession。
SqlSession是专门用来执行SQL语句的,是一个java程序和数据库之间的一次会话。
如何获取SqlSessionFactory对象呢?首先获取SqlSessionFactoryBuilder对象,通过这个对象的build()方法,来获取一个SqlSessionFactory对象。
依次的获取顺序:SqlSessionFactoryBuilder对象 > SqlSessionFactory对象 > SqlSession对象
3、在XML中构建 SqlSessionFactory
在Mybatis中有一个很重要的对象,这个对象就是:SqlSessionFactory对象,创建这个对象需要Xml文件。
XML是什么? 它是一个配置文件。
4、Mybatis中有两个重要的配置文件:
其中一个是: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="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--mapper标签的resource属性会自动从根路径下开始查找资源,用于指定某一个xml文件-->
<!--mapper标签可以有多个,即绑定多个xml文件-->
<mapper resource="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
另外一个是:XxxxMapper.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">
<!--指定映射的Mapper接口-->
<mapper namespace="org.mybatis.example.BlogMapper">
<!--标签有 select insert delete update ,对应查增删改,标签内写SQL语句-->
<!--id对应Mapper接口的方法名-->
<select id="methodName" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper>
2.2 关于Mybatis的事务管理机制深度剖析:
* 在mybatis-config.xml文件中,可以通过以下的配置进行mybatis的事务管理
<transactionManager type="JDBC">
* type属性的值包括两个:
JDBC
MANAGED
type后面的值,只有以上两个值可选,不区分大小写。
* 在mybatis中提供了两种事务管理机制:
第一种:JDBC事务管理器
第二种:Managed事务管理器
* JDBC事务管理:
mybatis框架自己管理事务,自己采用原生的JDBC代码去管理事务
conn.setAutoCommit(false); 关闭自动提交,表示开启事务
.....业务处理...
conn.commit(); 手动提交事务
* MANAGED事务管理器:
mybatis不再负责事务的管理,事务管理交给其他容器来负责,例如:spring。
对于我们当前的单纯的只有mybatis的情况下,如果配置为:MANAGED,那么事务这块是没人管的,没有其他框架管理事务的话表示事务压根没有开启。
2.3 一个较完整的mybatis程序
2.4 Mybatis集成Junit使用
1、引入依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
2、创建单元测试类,在测试方法上添加@Test注解,表示是一个单元测试方法
2.5 Mybatis如何集成日志?
mybatis核心配置文件中可以开启运行时行为,开启日志,通过settings标签
* mybatis常见的集成的日志组件有哪些呢?
SLF4J(沙拉风)
LOG4J
LOG4J2
STDOUT_LOGGING
......
* 其中STDOUT_LOGGING是标准日志,mybatis已经实现了这种标准日志,mybatis框架本身已经实现了这种标准。只要开启即可,怎么开启呢?在mybatis-config.xml文件中使用标签进行配置开启。
具体还可以设置哪些配置,参考:配置_MyBatis中文网
* 集成logback日志框架
logback日志框架实现了slf4j标准。(沙拉风:日志门面。日志标准)
引入这个可以不写mybatis-config.xml里的settings设置。
第一步:引入logback的依赖
<!--引入logback的依赖,这个日志框架实现了slf4j规范-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
第二步:引入logback所必须的xml配置文件(用于定义日志的级别和输出的日志格式),配置文件的名字,必须叫logback.xml或者logback-test.xml,不能是其他的名字。这个配置文件必须放在类的根路径下。
<?xml version="1.0" encoding="UTF-8"?>
<!-- 配置文件修改时重新加载,默认true -->
<configuration debug="false">
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder" charset="UTF-8">
<!-- 输出日志记录格式 -->
<pattern>[%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- mybatis log configure,对应的类输出的日志级别-->
<logger name="com.apache.ibatis" level="TRACE"/>
<logger name="java.sql.Connection" level="DEBUG"/>
<logger name="java.sql.Statement" level="DEBUG"/>
<logger name="java.sql.PreparedStatement" level="DEBUG"/>
<!-- 日志输出级别,LOGBACK日志级别包括五个:TRACE < DEBUG < INFO < WARN < ERROR-->
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</root>
</configuration>
2.6 MyBatis工具类的编写
public class SqlSessionUtil {
private static SqlSessionFactory sqlSessionFactory;
static {
SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
try {
sqlSessionFactory = factoryBuilder.build(Resources.getResourceAsStream("mybatis-config.xml"));
} catch (IOException e) {
e.printStackTrace();
}
}
//构造方法私有化
private SqlSessionUtil() {
}
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
第三章:使用MyBatis完成CRUD
3.1 如何给mapper.xml的sql语句动态传参
map集合方式
解决方法:传参,占位符获取参数。
//获取SqlSession对象
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
//将数据进行封装,这里封装成map集合
Map<String,Object> map = new HashMap<>();
map.put("arg1","10086");
map.put("arg2","雷克萨斯");
map.put("arg3",100.0);
map.put("arg4","2022-11-20");
map.put("arg5","燃油车");
//选择执行操作的方法,第一个参数指定id即执行的sql语句,第二个参数,sql语句的参数
int count = sqlSession.insert("insertCar",map);
System.out.println(count);
sqlSession.commit();
xml文件:
通过POJO对象传值
//获取SqlSession对象
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
//将数据进行封装,这里封装成POJO对象
Car car = new Car("10087","凯迪拉克",new BigDecimal(30),"2022-11-20","燃油车");
//选择执行操作的方法,第一个参数指定id即执行的sql语句,第二个参数,sql语句的参数
int count = sqlSession.insert("insertCar",car);
System.out.println(count);
sqlSession.commit();
xml文件:(通过属性的Get方法取值)
3.2 删除数据
//获取SqlSession对象
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
//选择执行操作的方法,第一个参数指定id即执行的sql语句,第二个参数,sql语句的参数
int count = sqlSession.delete("deleteCarById",2);
System.out.println(count);
sqlSession.commit();
xml文件:(当只有一个参数的时候,#{}里面的名字可以随便写)
3.3 修改数据
//获取SqlSession对象
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
//将需要数据的数据进行封装,这里封装成POJO对象
Car car = new Car(5,"10087","凯迪拉克",new BigDecimal(50),"2022-11-20","电车");
//选择执行操作的方法,第一个参数指定id即执行的sql语句,第二个参数,sql语句的参数
int count = sqlSession.update("updateCarById",car);
System.out.println(count);
sqlSession.commit();
xml文件:
3.4 查询数据
查询一条记录
需要特别注意的是,select标签中的resultType属性,用来告诉mybatis将查询的结果集封装成什么类型的java对象。
resultType属性的值通常写的是全限定类名
//获取SqlSession对象
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
//mybatis底层执行了select语句之后,一定会返回一个结果集对象,ResultSet
//JDBC中叫做ResultSet,接下来就是mybatis应该从ResultSet中拿数据,封装成POJO对象
Object car = sqlSession.selectOne("selectCarById", 7);
System.out.println(car);
xml文件:
结果:
发现了问题,为什么只有id和brand有数据呢?其他没有赋上值呢?
细心的会发现,没有值的属性都有一个共同点,就是的属性名字和数据库的字段名不一致,所以导致赋不上值。
解决方法:(现在这种方法先知道,后续有学到xml文件的标签使用的时候有更简单的方法,但是原理都是一样的)。
修改select语句,将查询的到的结果的字段名,使用as 来修改字段名,改成和java对象的属性名一致。
查询多条记录
//获取SqlSession对象
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
//mybatis底层执行了select语句之后,一定会返回一个结果集对象,ResultSet
//JDBC中叫做ResultSet,接下来就是mybatis应该从ResultSet中拿数据,封装成POJO对象
//和其他方法类似,有参数的话就调用两个参数的方法
List<Object> selectAll = sqlSession.selectList("selectAll");
//遍历输出
selectAll.forEach(item->{
System.out.println(item);
});
xml文件:
结果:
3.5 SQL Mapper映射文件中的namespace作用
在 sql mapper.xml文件中有一个namespace,这个属性是用来指定命名空间的,用来防止id重复
Mapper映射文件中是可以有多个的,在多个Mapper映射文件中,如果有相同的id,就会出问题,不知道执行哪一个了。
命名空间是来防止id的冲突的,所以我们可以把 namespace来当作区别Mapper映射文件的标识。
因此我们在操作sqlSession去调用sql语句的时候,也可以加入namespace
第四章: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">
<!--根标签-->
<configuration>
<!--java.util.Properties类,是一个Map集合,key和value都是String类型-->
<!--properties标签中可以配置很多的属性-->
<properties>
<!--这里类似于定义类的属性,赋值,在下面可以进行引用-->
<!--如何引用? ${属性名} -->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhsot:3306/mybatis3"/>
<!--除了在这里进行定义和赋值外?还可以引入properties文件-->
<!--在properties标签中添加 resource属性,指定properties文件路径-->
</properties>
<!--配置标签-->
<settings>
<!--子配置标签,可以有多个,设置具体配置的标签-->
<setting name="" value=""/>
</settings>
<!--数据库环境标签,这个标签的 default 属性指定的值就是创建SqlSessionFactory对象的时候,
没有使用两个参数的build方法指定数据库环境的话的,就采用这个默认的数据库环境-->
<environments default="developmentOne">
<!--一般情况下,一个环境会对应一个SqlSessionFactory对象-->
<!--具体环境的标签,可以有多个,一个标签一个环境-->
<environment id="developmentOne">
<!--事务管理器:
1、指定mybatis具体使用什么方式管理事务。
2、type属性有两个值:
第一个:JDBC-》使用原生的JDBC代码来管理事务。
conn.setAutoCommit(false)
......
conn.commit()
第二个:MANAGED-》mybatis不再负责事务的管理,将事务管理交给其他的JEE(JavaEE)容器,例如:spring
3、不区分大小写,但是不能写其他值,只能是二选一
-->
<transactionManager type="JDBC"/>
<!--
dataSource配置:
1、dataSource被成为数据源。
2、dataSource作用是什么?为程序提供Connection对象(凡是给程序提供Connection对象的,都是叫作数据源)。
3、数据源实际上是一套规范,JDK中有这样一套规范。
4、我们自己也可以编写数据源组件,只要实现javax.sql.DataSource接口就行,实现接口当中的所有方法,这样就有了自己的数据源
比如你可以写一个属于自己的数据库连接池(数据库连接池是提供连接对象的,所以数据库连接池就是一个数据源)。
5、常见的数据源组件有哪些呢?
阿里巴巴的德鲁伊连接池:druid
c3p0
dbcp
......
6、type属性用来指定数据源的类型,就是具体指定什么方式来获取Connection对象:
type属性值三选一:UNPOOLED、POOLED、JNDI
UNPOOLED:不使用数据库连接池技术,每次需要的时候,都是创建新的Connection对象。
POOLED:使用mybatis自己实现的数据库连接池
JNDI:集成第三方的数据库连接池
type不同,dataSource标签内的子标签也不一样: 具体参照:https://mybatis.net.cn/configuration.html#databaseIdProvider
-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis3?serverTimezone=GMT%2B8"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
<!--配置信息
poolMaximumActiveConnections,连接池中最多的正在使用的连接对象的上限,默认值是10
-->
<property name="poolMaximumActiveConnections" value="3"/>
</dataSource>
</environment>
<!--具体环境的标签,可以有多个,一个标签一个数据库环境-->
<environment id="developmentTwo">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis2222?serverTimezone=GMT%2B8"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--mapper标签的resource属性会自动从根路径下开始查找资源,用于指定某一个xml映射文件文件-->
<mapper resource="CarMapper.xml"/>
<!--指定xml映射文件所在的包,可以大批量的指定xml-->
<package name="com.wang.mapper"/>
</mappers>
</configuration>
第五章:手写MyBatis框架(大致了解掌握原理)
5.1 dom4j解析xml文件
引入依赖
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.1</version>
</dependency>
简单使用
//创建SAXReader对象
SAXReader reader = new SAXReader();
//获取输入流
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("xml文件路径");
//读xml文件,返回document对象,document对象是文档对象,代表了整个xml文件
Document document = reader.read(is);
//获取文档对象的根标签
Element rootElement = document.getRootElement();
//获取根节点的名字
rootElement.getName();
//xpath是做标签路径匹配的,能给让我们快手定位XML文件中的元素。
//以下xpath代表了,从根下开始找configuration标签,然后找configuration标签下的子标签environments
String xpath = "/configuration/environments";
//原来是Node类,强转成Element,Element是Node类的子类,方法更多
Element environments = (Element)document.selectSingleNode(xpath);
//获取属性的值
environments.attributeValue("标签内的属性名");
//当configuration标签下的environments标签有两个相同的子标签environment,如何获取指定的那个呢?
String xpath2 = "/configuration/environments/environment[@属性名='"+属性值+"']";
Element environment = (Element)document.selectSingleNode(xpath2);
//获取某标签下的指定子标签
Element subElement = environment.element("标签名");
//获取标签来的所有子标签
List<Element> elements = environment.elements();
//不想从根下开始,去获取所有的某个标签
String xpath3 = "//标签名";
List<Node> nodes = document.selectNodes(xpath3);
5.2 引入相关依赖
<dependencies>
<!--解析xml文件依赖-->
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.1.3</version>
</dependency>
<!--xpath类库-->
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.2.0</version>
</dependency>
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
5.3 读取mybatis-config.xml配置文件
@Test
public void ParseMyBatisConfigXml() throws Exception {
//创建SAXReader对象
SAXReader reader = new SAXReader();
InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream("mybatis-config.xml");
//xml对象
Document document = reader.read(in);
String xPath = "/configuration/environments";
Element environments = (Element) document.selectSingleNode(xPath);
String default = environments.attributeValue("default");
xPath = "/configuration/environments/environment[@id='"+default +"']";
Element environment = (Element) document.selectSingleNode(xPath);
Element transactionManager = environment.element("transactionManager");
//事务类型
String transactionType = transactionManager.attributeValue("type");
List<Element> dataSources = environment.element("dataSource").elements();
//打印连接源
dataSources.forEach(properties ->{
String name = properties.attributeValue("name");
String value = properties.attributeValue("value");
// TODO 提取数据出来封装
});
//mapp映射文件路径
xPath = "//mapper";
List<Node> elements = document.selectNodes(xPath);
elements.forEach(element -> {
Element mapper = (Element) element;
String resource = mapper.attributeValue("resource");
// TODO 提取数据出来封装
});
}
5.4 读取CarMapper.xml文件
/**
* 解析CarMapper.xml文件
*/
@Test
public void ParseSqlConfigXml() throws Exception {
SAXReader reader = new SAXReader();
InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream("CarMapper.xml");
Document document = reader.read(in);
Element mapper = document.getRootElement();
System.out.println(mapper.attributeValue("namespace"));
List<Element> elements = mapper.elements();
elements.forEach(element -> {
System.out.println(element.attributeValue("id"));
String sql = element.getTextTrim();
//简单正则表达式:[a-zA-Z0-9_$]* 表示数字+字母+下划线,数量是*个
System.out.println(sql.replaceAll("#\\{[a-zA-Z0-9_$]*}","?"));
});
}
5.5 创建基础类
//编写Resources类
public class Resources {
private Resources(){};
public static InputStream getResourceAsReader(String classPath){
return ClassLoader.getSystemClassLoader().getResourceAsStream(classPath);
}
}
//创建SqlSessionFactoryBuild类,其中需要SqlSessionFactory类对象
public class SqlSessionFactoryBuilder {
public SqlSessionFactoryBuilder(){};
public SqlSessionFactory build(){
return null;
}
}
public class SqlSessionFactory {
/**
* 事务管理器
*/
private Transaction transaction;
/**
* 存放sql语句的map集合
* key是sqlId
* value是对应的sql标签信息对象
*/
Map<String,MappedStatement> mappedStatements;
}
public class JdbcTransaction implements Transaction{
@Override
public void commit() {
connection.commit();
}
@Override
public void rollback() {
connection.rollback();
}
@Override
public void close() {
connection.close();
}
}
/**
* @author huochai
* @date 2022/10/15 16:45
* 不使用连接池,主要实现这个数据源
*/
public class UnPooledDataSource implements DataSource {
private String url;
private String username ;
private String password ;
public UnPooledDataSource(String url, String username, String password) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
this.url = url;
this.username = username;
this.password = password;
}
@Override
public Connection getConnection() throws SQLException {
return null;
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
}
第六章:在WEB中应用MyBatis
目标:
* 掌握mybatis在web应用中怎么去使用
* mybatis三大对象的作用域和生命周期
* ThreadLocal原理以及使用
* 巩固MVC架构模式
* 为学习Mybatis的接口代理机制做准备
6.1 创建java web项目,引入依赖,配置Tomcat启动、核心xml文件,映射xml文件。
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
metadata-complete="false"><!--这里写false表示支持 @WebServlet注解也支持映射,如果为true表示要在文件中配置servlet映射-->
</web-app>
使用方式和普通java程序类似,只不过Java Web项目按照三层架构来开发。
创建SqlSessionFactoryBuild -》 SqlSessionFactory -》 SqlSession
创建Servlet处理请求。接收参数,表示层调用业务层,业务层调持久层,持久层使用mybatis操作数据库数据。
6.2 整体结构
6.3 前后端代码实现
6.3.1 前端
6.3.2 后端
实体类
public class Account {
private Long id;
private String actno;
private Double balance;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getActno() {
return actno;
}
public void setActno(String actno) {
this.actno = actno;
}
public Double getBalance() {
return balance;
}
public void setBalance(Double balance) {
this.balance = balance;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", actno='" + actno + '\'' +
", balance=" + balance +
'}';
}
}
表示层
@WebServlet("/transfer")
public class AccountServlet extends HttpServlet {
//为了让这个对象在其他方法中也可以调用,声明为实例遍历
private AccountService accountService = new AccountServiceImpl();
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取表单数据
String fromActno = request.getParameter("fromActno");
String toActno = request.getParameter("toActno");
Double money = Double.valueOf(request.getParameter("money"));
//表示层不处理业务逻辑的,而是调用service(业务层)的转账方法完成转账,
accountService.transfer(fromActno,toActno,money);
//调用View完成展示结果
}
}
业务层
接口
/**
* 面向接口,创建一个接口 账户业务类
* 业务类当中的业务方法的名字在起名的时候,最好见名知意,能够体现出具体的业务是做什么的
*/
public interface AccountService {
/**
* 账户转账业务
* @param fromActno 转出账户
* @param toActno 转入账户
* @param money 金额
*/
void transfer(String fromActno,String toActno,double money);
/**
* 查询用户
* @param id
* @return
*/
Account selectById(Long id);
}
实现类
public class AccountServiceImpl implements AccountService { @Override public void transfer(String fromActno, String toActno, double money) { //这个类负责处理业务 //判断转出账户的余额是否充足(查询) //转出账户余额不足 //转出账户余额充足,更新转出账户余额 //更新转入账户余额 } @Override public Account selectById(Long id) { //根据id查询用户 return null; } }
持久层
接口
/**
* 账户Mapper(Dao)对象,负责对数据库的数据进行操作
* Mapper(Dao)对象中的任何一个方法和业务都不挂钩,没有业务逻辑在里面,
* Dao中的方法就是CRUD,不含业务逻辑代码,对数据库的操作不会被业务逻辑代码影响,这样增加了代码的复用性。
*/
public interface AccountMapper {
/**
* 账户转账业务
* @param fromActno 转出账户
* @param toActno 转入账户
* @param money 金额
*/
int transfer(String fromActno,String toActno,double money);
/**
* 查询用户
* @param id
* @return
*/
Account selectById(Long id);
}
实现类
//后续这个类(Mapper的实现类)可以不写了
public class AccountMapperImpl implements AccountMapper {
@Override
public int transfer(String fromActno, String toActno, double money) {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
//进行数据库操作
return 0;
}
@Override
public Account selectById(Long id) {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
//进行数据库操作
return null;
}
}
6.4 WEB应用下mybatis的事务控制
在处理业务的时候会执行多个操作数据库的sql语句,要确保使用的SqlSession是同一个,并且需要在业务代码都执行完的最后再提交事务。
如何确保是用一个SqlSession呢?
除了给Mapper层的每个方法添加一个SqlSession形参之外,还可以使用我们的ThreadLoad
业务逻辑处理开始之前创建SqlSession,然后将SqlSession对象放进到ThreadLoad中。
后续在持久层中需要用到的时候,直接在ThreadLoad中拿。
ThreadLoad对象定义在哪里呢?定义才SqlSessionUtil中的,定义成静态变量,getSqlSession方法获取的时候,先通过threadLoad.get()判断ThreadLoad中的sqlSession是否为空,如果为空的话就创建,然后threadLoad.set(sqlSession)放进ThreadLoad中,如果不为空就直接threadLoad.get()拿。 关闭的时候要记得从ThreadLoad中移除thread.remove()。
6.5 mybatis三大对象的作用域和生命周期
第七章:MyBatis中接口代理对象使用
通过接口代理对象,使用mybatis框架的时候就不需要我们去创建Dao(Mapper)接口的实现类了。只要定义接口的方法,然后编写xml文件即可。
7.1 xml映射文件:需要满足一定的规则
namespace:必须是Dao接口的全限定名称
id:必须是Dao接口的方法名
为什么呢:因为mybatis框架创建Dao接口的实现代理对象的时候,实现接口的方法的实现代码是通过自己的规则使用接口名和方法名去调用xml文件对应的sql语句的,默认将接口名全限定名称当作namespace,实现的方法名为id。
7.2 如何获取到代理对象
7.3 使用
直接调用返回对象的相应得方法,就会执行xml文件中相应的sql语句。
第八章:MyBatis小技巧
8.1 #{}和${}的区别
#{}:底层使用PreparedStatement。特点:先进行SQL语句的编译,然后给SQL语句的占位符?传值。可以避免SQL注入的风险(优先使用这个,避免SQL注入的风险)
${}:底层使用Statement。特点:先进行SQL语句的拼接,然后再对SQL语句进行编译。存在SQL注入的风险(当需要接收前端动态传值的进行拼接sql语句的时候使用这个,例如 升序或降序 asc desc )。
8.2 查找包含某个关键词str的方法
1、用引号把通配符引出去,让#{}在外面好被jdbc检测到
<select id="selectByLike" resultType="com.powernode.mybatis.pojo.Car">
select id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carType
from t_car
where car_type like "%"#{str}"%"
</select>
2、使用concat()函数
<select id="selectByLike" resultType="com.powernode.mybatis.pojo.Car">
select id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carType
from t_car
where car_type like Concat('%',#{str},'%')
</select>
8.3 typeAliases 别名
在xml映射映射配置文件中类似于resultType=""属性赋值,是需要我们去写类的全限定名称的(namespace除外,namespace是不能使用别名的),为了简便,我们可以采用区别名的方法,即给全限定类名起一个简单短小的名字。在xml文件中使用。
配置方法:
在xml核心配置文件中的一个标签
8.4 Mapper的配置
<mappers>
<!--1. 项目的根路径下查找CarMapper.xml文件-->
<mapper resource="CarMapper.xml"/>
<!--2. 电脑的绝对路径查找,使用极少,移植性太差-->
<mapper url="file://c:/CarMapper.xml"/>
<!--3. 全限定接口名,查找映射接口同级目录下的Mapper.xml文件。
这种前提,xml文件和接口要在同一个包中,xml文件前缀名字要和接口名字一样
可以在resource文件夹下建一个包,路径和接口路径一样
使用这个路径com/powernode/mybatis/mapper (建多重目录)
而不是com.powernode.mybatis.mapper (这个建的方法只是一层目录)
-->
<!-- com/powernode/mybatis/mapper 建包需要这样建-->
<mapper class="com.powernode.mybatis.mapper.CarMapper"/>
<!--最常用:包路径下自动查找接口对应名字xml文件,建包方式和上面一样-->
<package name="com.powernode.mybatis.mapper"/>
</mappers>
8.5 IDEA配置文件模板
左上角 File --> settings --> Editor --> File and Code Templates
然后点击 + 号 取名 粘贴模板内容 点击 ok。
下次需要的时候点击需要创建文件所在的目录文件夹使用快捷键,ALT + insert 找到模板创建文件就可了。
8.6 插入数据的时候获取当时插入的数据的主键
在xml映射文件中配置
第九章:MyBatis参数处理
9.1 单个简单类型参数
parameterType表示传入参数的类型,这里可以用别名Long,官方文档有别名可以参考,Long类型是mybatis已经提供了别名的。(这个parameterType大部分情况下可以省略,mybatis会进行类型推断)
9.2 参数为Map类型或者POJO类
map类
POJO类
9.3 多个参数的情况
方法上有多个参数的时候 parameterType就可以不写了。
传参方法有两种:
第一种:如果是多个参数的话,mybatis框架的底层会创建一个Map集合,并且Map集合是以这种方式存储参数的:(两种key都可以拿,属于同一个map集合)。
map.put("arg0",name); map.put("arg1",age); map.put("arg2",sex);
map.put("param1",name); map.put("param2",age); map.put("param3",sex);
因此取值方式就和Map的取值方式一样,只不过key是按照mybatis创建的去取,arg0、arg1...或者param1、param2。
第二种:通过注解@Param
在接口的方法形参前面加上@Param注解 指定这个参数在map集合中对应的key是什么。
使用了@Param注解后 arg0、arg1没有了 但是param1、param2还是可以用的。
9.4 @Param源码分析
第十章:Mybatis查询语句专题
将查询的数据封装结果集的操作 resultType=”“
10.1 返回结果集封装成实体类
10.2 返回结果集封装成多个实体类
写法和返回一条数据一样,resultType指定实体类就行,如果是多条mybatis会封装成List集合。但是接口方法上的返回值类型需要是List集合。 一条记录却可以用List集合接收。
10.3返回结果没有合适的实体类,这时候我们可以指定Map集合接收
一条数据 Map<String,Object> 和 多条数据 List<Map<String,Object>>
封装成大Map Map<String,Map<String,Object>>
10.4 结果集映射(指定使用结果集映射,将数据库字段名和Java类属性一一对应)
结果集映射使用:
10.5 开启驼峰命名自动映射
在xml核心配置文件中配置:
第十一章:动态SQL
有时候我们有需求,一个接口的方法可以动态的执行SQL语句,而不是写死的SQL语句,这时候就需要我们使用动态SQL了。
例如多条件查询,比如查询的时候我们根据某个字段查询,根据日期查,或者根据主键和日期查询,或者根据主键和名字查询.....等,这么多的组合条件,如果是写死的SQL语句的话,我们要对应每种情况去写一条SQL语句,这样就会很麻烦,影响开发效率。
这时候动态SQL就能发挥它的作用了。
11.1 if 标签
11.2 where 标签
if 标签 配合这个 where标签的话 where 1=1 则不用写了,而且如果where后面 拼接了and 或者or的话,会去除掉。
11.3 trim 标签
<select id="selectByMultiCasesByTrim" resultType="car">
select * from t_car
<!--
在trim标签的前面或者后面->
prefix:增加前缀
suffix:增加后缀
prefixOverrides:删除前缀
suffixOverrides:删除后缀
-->
<!--以下表示 如果这里面不为空则以where开头,然后把标签内的内容,如果有以and
或者 or 结尾的话 去除后缀-->
<trim prefix="where" prefixOverrides="and|or" suffixOverrides="and|or">
<if test="brand != null and brand != ''">
and brand like "%"#{brand}"%"
</if>
<if test="guidePrice != null and guidePrice != ''">
and guide_price > #{guidePrice}
</if>
<if test="carType != null and carType != ''">
and car_type = #{carType}
</if>
</trim>
</select>
11.4 set标签
主要使⽤在update语句当中,⽤来⽣成set关键字,同时去掉最后多余的“,”
⽐如我们只更新提交的不为空的字段,如果提交的数据是空或者"",那么这个字段我们将不更新。
11.5 choose标签
<choose>
<when></when>
<when></when>
<when></when>
<otherwise></otherwise> //如果都不符合,就走这个
</choose>
//等同于
if(){
}else if(){
}else if(){
}else if(){
}else{
}
11.6 foreach 标签
批量删除
<!--
foreach标签的属性:
collection:指定数组或者集合参数名,要在接口处添加Param("ids")才能接收到ids
item:代表数据或集合中的元素
separator:循环之间的分隔符
open:foreach循环拼接的所有sql语句的最前面以什么开始
close:foreach循环拼接的所有sql语句的最后面以什么结束
-->
<delete id="deleteByIds">
delete from t_car where id in
<foreach collection="ids" separator="," open="(" close=")" item="id">
#{id}
</foreach>
</delete>
批量插入
<insert id="insertMatch">
insert into t_car values
<foreach collection="cars" item="car" separator=",">
(null,#{car.carNum},#{car.brand},#{car.guidePrice},#{car.produceTime},#{car.carType})
</foreach>
</insert>
11.7 Sql标签与include标签
sql标签⽤来声明sql⽚段
include标签⽤来将声明的sql⽚段包含到某个sql语句当中
第十二章:Mybatis高级映射以及延迟加载
12.1 多对一高级映射的三种方法:
类中存在另外一个类型的属性,如何将结果集直接映射呢?
第一种:级联属性映射
第二种:采用association标签
第三种:分步查询(这种方法常用,优点一可复用,优点二支持懒加载)
column属性值写的是数据库的字段名
一般在mybatis-config.xml核心配置文件中设置全局懒加载选项
<settings>
<!--开启全局延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
12.2 一对多映射高级映射的两种种方法:
第一种方式(连表查询用collection封装)
<resultMap id="clazzResultMapCollection" type="clazz">
<id property="cid" column="cid"/>
<result property="cname" column="cname"/>
<!--
property:集合变量名称
ofType:集合中元素的名称
-->
<collection property="students" ofType="student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
</collection>
</resultMap>
<select id="selectByCidCollection" resultMap="clazzResultMapCollection">
select c.cid,c.cname,s.sid,s.sname from t_clazz c left join t_stu s on c.cid=s.cid where c.cid=#{cid}
</select>
第二种方式(分布查询)column属性值写的是数据库的字段名
<resultMap id="clazzResultMapStep" type="clazz">
<id property="cid" column="cid"/>
<result property="cname" column="cname"/>
<!--
一对多,这里是collection,collection是集合的意思
ofType 属性用来指定集合当中的元素类型
-->
<collection property="students" ofType="student" select="com.powernode.mybatis.mapper.StuMapper.selectByCid" column="cid" >
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
</collection>
</resultMap>
<select id="selectByCidStep" resultMap="clazzResultMapStep">
select cid,cname from t_clazz where cid=#{cid}
</select>
第十三章:Mybatis缓存
缓存:cache
缓存的作⽤:通过减少IO的⽅式,来提⾼程序的执⾏效率。
mybatis的缓存:将select语句的查询结果放到缓存(内存)当中,下⼀次还是这条select语句的话,直接从缓存中取,不再查数据库。⼀⽅⾯是减少了IO。另⼀⽅⾯不再执⾏繁琐的查找算法。效率⼤⼤提升。
mybatis缓存包括:
* ⼀级缓存:将查询到的数据存储到SqlSession中。
* ⼆级缓存:将查询到的数据存储到SqlSessionFactory中。
* 或者集成其它第三⽅的缓存:⽐如EhCache【Java语⾔开发的】、Memcache【C语⾔开发的】
等。
缓存只针对于DQL语句,也就是说缓存机制只对应select语句。
13.1 一级缓存
一级缓存默认是开启的,不需要做任何配置。
原理:只要使用同一个SqlSession对象执行同一条SQL语句,就会走缓存。
思考:什么时候不走缓存?
* SqlSession对象不是同一个,不走缓存
* 查询条件不一样,肯定不走缓存
思考:什么时候缓存失效?
* 第一次DQL和第二次DQL之间做了以下两件事中的任意一件,都会让一级缓存清空
* 执行了sqlSession的clearCache()方法,这是手动清空缓存。
* 执行了Insert或者delete或者update语句,不论是操作哪张表,都会清空一级缓存。
13.2 二级缓存
⼆级缓存的范围是SqlSessionFactory。
使⽤⼆级缓存需要具备以下⼏个条件:
1、全局性地开启或关闭所有映射器配置⽂件中已配置
的任何缓存。默认就是true,⽆需设置。
<setting name="cacheEnabled" value="true">
.2、在需要使⽤⼆级缓存的SqlMapper.xml⽂件中添加配置:
<cache />
3、使⽤⼆级缓存的实体类对象必须是可序列化的,也就是必须实现java.io.Serializable接⼝
4、SqlSession对象关闭或提交之后,⼀级缓存中的数据才会被写⼊到⼆级缓存当中。此时⼆级缓存才可⽤。
一级缓存未关闭和提交情况下
一级缓存关闭和提交情况下,(先找一级缓存,再找二级缓存)
⼆级缓存的失效:只要两次查询之间出现了增删改操作。⼆级缓存就会失效。【⼀级缓存也会失效】
<cache>标签的有以下属性:
eviction:指定从缓存中移除某个对象的淘汰算法。默认采⽤LRU策略。
LRU:Least Recently Used。最近最少使⽤。优先淘汰在间隔时间内使⽤频率最低的对象。(其
实还有⼀种淘汰算法LFU,最不常⽤。)
FIFO:First In First Out。⼀种先进先出的数据缓存器。先进⼊⼆级缓存的对象最先被淘汰。
SOFT:软引⽤。淘汰软引⽤指向的对象。具体算法和JVM的垃圾回收算法有关。
WEAK:弱引⽤。淘汰弱引⽤指向的对象。具体算法和JVM的垃圾回收算法有关。
flushInterval:
⼆级缓存的刷新时间间隔。单位毫秒。如果没有设置。就代表不刷新缓存,只要内存⾜够⼤,⼀直会向⼆级缓存中缓存数据。除⾮执⾏了增删改。
readOnly:
true:多条相同的sql语句执⾏之后返回的对象是共享的同⼀个。性能好。但是多线程并发可能
会存在安全问题。
false:多条相同的sql语句执⾏之后返回的对象是副本,调⽤了clone⽅法。性能⼀般。但安
全。
size:
设置⼆级缓存中最多可存储的java对象数量。默认值1024。
13.3 集成Ehcache
集成EhCache是为了代替mybatis⾃带的⼆级缓存。⼀级缓存是⽆法替代的。
mybatis对外提供了接⼝,也可以集成第三⽅的缓存组件。⽐如EhCache、Memcache等。都可以。
EhCache是Java写的。Memcache是C语⾔写的。所以mybatis集成EhCache较为常⻅,按照以下步骤操
作,就可以完成集成:
第⼀步:引⼊mybatis整合ehcache的依赖。
<!--mybatis集成ehcache的组件-->
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.2</version>
</dependency>
<!--ehcache需要slf4j的⽇志组件,log4j不好使-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
<scope>test</scope>
</dependency>
第⼆步:在类的根路径下新建echcache.xml⽂件,并提供以下配置信息
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
<!--磁盘存储:将缓存中暂时不使⽤的对象,转移到硬盘,类似于Windows系统的虚拟内存-->
<diskStore path="e:/ehcache"/>
<!--defaultCache:默认的管理策略-->
<!--eternal:设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有
效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断-->
<!--maxElementsInMemory:在内存中缓存的element的最⼤数⽬-->
<!--overflowToDisk:如果内存中数据超过内存限制,是否要缓存到磁盘上-->
<!--diskPersistent:是否在磁盘上持久化。指重启jvm后,数据是否有效。默认为false-
->
<!--timeToIdleSeconds:对象空闲时间(单位:秒),指对象在多⻓时间没有被访问就会失
效。只对eternal为false的有效。默认值0,表示⼀直可以访问-->
<!--timeToLiveSeconds:对象存活时间(单位:秒),指对象从创建到失效所需要的时间。
只对eternal为false的有效。默认值0,表示⼀直可以访问-->
<!--memoryStoreEvictionPolicy:缓存的3 种清空策略-->
<!--FIFO:first in first out (先进先出)-->
<!--LFU:Less Frequently Used (最少使⽤).意思是⼀直以来最少被使⽤的。缓存的元
素有⼀个hit 属性,hit 值最⼩的将会被清出缓存-->
<!--LRU:Least Recently Used(最近最少使⽤). (ehcache 默认值).缓存的元素有⼀
个时间戳,当缓存容量满了,⽽⼜需要腾出地⽅来缓存新的元素的时候,那么现有缓存元素中时间戳
离当前时间最远的元素将被清出缓存-->
<defaultCache eternal="false" maxElementsInMemory="1000" overflowToDis
k="false" diskPersistent="false"
timeToIdleSeconds="0" timeToLiveSeconds="600" memoryStor
eEvictionPolicy="LRU"/>
</ehcache>
第三步:修改SqlMapper.xml⽂件中的标签,添加type属性。
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
第十四章:逆向工程
14.1 代码生成
所谓逆向工程是:根据数据库表逆向自动生成pojo类、Mapper类,Mapper.xml 文件自动生成增删改查代码。
1、再pom.xml文件中配置环境:
<!--定制构建过程-->
<build>
<!--可配置多个插件-->
<plugins>
<!--其中的一个插件:mybatis逆向工程插件-->
<plugin>
<!--插件的GAV坐标-->
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.4.1</version>
<!--允许覆盖-->
<configuration>
<overwrite>true</overwrite>
</configuration>
<!--插件的依赖-->
<dependencies>
<!--mysql驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
2、新建generatorConfig.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>
<!--
targetRuntime有两个值:
MyBatis3Simple:生成的是基础版,只有基本的增删改查。
MyBatis3:生成的是增强版,除了基本的增删改查之外还有复杂的增删改查。
-->
<context id="DB2Tables" targetRuntime="MyBatis3">
<!--防止生成重复代码-->
<plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin"/>
<commentGenerator>
<!--是否去掉生成日期-->
<property name="suppressDate" value="true"/>
<!--是否去除注释-->
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--连接数据库信息-->
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/powernode"
userId="root"
password="root">
</jdbcConnection>
<!-- 生成pojo包名和位置 -->
<javaModelGenerator targetPackage="com.powernode.mybatis.pojo" targetProject="src/main/java">
<!--是否开启子包-->
<property name="enableSubPackages" value="true"/>
<!--是否去除字段名的前后空白-->
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- 生成SQL映射文件的包名和位置 -->
<sqlMapGenerator targetPackage="com.powernode.mybatis.mapper" targetProject="src/main/resources">
<!--是否开启子包-->
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- 生成Mapper接口的包名和位置 -->
<javaClientGenerator
type="xmlMapper"
targetPackage="com.powernode.mybatis.mapper"
targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!-- 表名和对应的实体类名-->
<table tableName="t_car" domainObjectName="Car"/>
</context>
</generatorConfiguration>
3、启动生成
14.2QBC(Query By Criteria)查询风格。
public void test(){
SqlSession session = SqlSessionUtil.openSession();
CarMapper mapper = session.getMapper(CarMapper.class);
//根据主键查询一个结果
Car car = mapper.selectByPrimaryKey(20L);
System.out.println(car);
//null表示没有条件所以是查询所有结果
List<Car> cars = mapper.selectByExample(null);
cars.forEach(car1 -> System.out.println(car));
// 根据条件查询结果(QBC query by criteria查询风格
// Example用于封装查询条件的,添加查询条件
CarExample carExample = new CarExample();
carExample.createCriteria()
.andBrandLike("比亚迪")
.andGuidePriceBetween(new BigDecimal(0),new BigDecimal(40));
//添加or
carExample.or().andCarTypeLike("技术车");
//最终sql语句:select * from t_car where (brand like "%比亚迪%" and guide_price>=0 and guide_price<40) or (car_type like "%技术车%")
List<Car> cars1 = mapper.selectByExample(carExample);
cars1.forEach(car1 -> System.out.println(car1));
session.close();
}
第十五章:Pagehelper
15.1 limit分页
15.2 PageHelper插件
PageHelper插件可以很方便的管理和使用分页
依赖:
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.1</version>
</dependency>
mybatis核心配置文件添加:
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
使用:
@Test
public void test(){
SqlSession session = SqlSessionUtil.openSession();
CarMapper mapper = session.getMapper(CarMapper.class);
//查询第二页,前三条记录
PageHelper.startPage(2,3);
List<Car> cars = mapper.selectAll();
//查看分页信息,可以获取到分页的其他信息,例如 总条数等等...
PageInfo<Car> pageInfo = new PageInfo<>(cars);
System.out.println(pageInfo);
session.close();
}
第十六章:注解式开发
注解式开发主要使用在简单的单表的CRUD操作,可以减少Sql映射文件的配置,但是不适合复杂操作。(简单使用注解,复杂的用xml)
16.1 @Insert @Delete @Update @Select注解
@Insert( "insert into t_car values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})")
int insertCar(Car car);
@Delete("delete from t_car where id=#{id}")
int deleteById(Long id);
@Update("update t_car set car_num=#{carNum},brand=#{brand},guide_price=#{guidePrice},produce_time=#{produceTime},car_type=#{carType} where id=#{id}")
int updateById(Car car);
@Select("select * from t_car where id=#{id}")
Car selectById(Long id);
@Test
public void insertCar(){
SqlSession session = SqlSessionUtil.openSession();
CarMapper mapper = session.getMapper(CarMapper.class);
Car car = new Car(null,"10377","报道33车1",35.0,"2022-12-05","技术车");
mapper.insertCar(car);
session.commit();
session.close();
}