阶段六-Day03-MyBatis

一、框架介绍

1. 框架的作用

将许多项目封装起来,形成了框架

2. 框架的优缺点

1. 优点
1.1 更好用

框架都是对Java原生内容进行的封装,对于企业级项目开发来说,使用框架比使用原生Java更好用,写起来更简单。

1.2 更强大

框架封装过程中会内置一些常见必要逻辑或功能,所以在使用框架时很多能够不需要再次编码,框架本身就带有这些功能了。

1.3 开发周期更短

由于框架使用起来更加简单,必定会在一定程度上缩短程序的开发周期。很多IT公司最大的成本都是人员成本,缩短了项目的开发周期,对于企业来说利润更高。这也是企业为什么都喜欢使用框架的最主要原因之一。

2. 缺点
2.1 更多的学习成本

不同的框架由不同的公司或组织开发与维护,不同公司或组织有着不同的习惯和规则,想要使用框架就需要学习框架如何使用,学习这些框架里面的要求。

2.2 初学者更容易出错

因为框架里面都封装了很多内容,想要使用框架就必须按照框架的规则进行使用。对于初学者如果不去记忆里面的规则,自己随意发挥,很容易出错。

所以想要错误更少,学习框架时必须严格按照老师讲的去做,严格按照框架规则去使用。

2.3 对于初学者,出了错误更难解决

因为框架都是深度封装,对于开发者来说可能只写了一行代码,但这一行代码里面可能是几百或几千行代码的封装。一旦报错了,如果不知道框架原理是不太好解决的。

所以想要更好的解决出现的问题,就必须要跟着老师学习框架的原理,同时要对每次出现的错误进行整理记忆,下次在出现这个错误的时候就可以快速解决了。

4. Java中的常见框架

Java项目无论是否使用框架,多采用MVC开发模型,一个项目被分为多层。一个Java框架可能只负责里面的一层。

一个Java项目并不是使用一个框架就可能完成的,通常需要很多框架配合使用,才能实现一个完整的项目。

常见Java框架分类(不仅仅就这些,列举一些常见的):

(1)持久层框架:MyBatis、Hibernate、Spring Data、iBatis。

(2)MVC框架:Spring MVC、Struts1、Struts2。

(3)项目管理框架:Spring Framework、Spring Boot。

(4)微服务框架:Spring Cloud。

(5)权限管理框架:Spring Security、Shiro。

并不是每个项目都需要把上面所有分类都使用上,不同的项目可能只会使用里面几个分类,但是只要使用了其中某个分类,只会选择其中一个。

常见的组合:

(1)SSM:Spring Framework + Spring MVC + MyBatis。最常见组合,属于Java程序员必须掌握的内容。

(2)SSMP:Spring Framework + Spring MVC + MyBatis+MyBatis Plus。对SSM的增强,减少SQL的编写。

(3)SSI:Spring Framework + Spring MVC/Struts1/Struts2 + iBatis。SSM的上代组合,目前很少出现。

(4)SSH:Spring Framework + Struts1/Struts2 + Hibernate。和SSI属于同时代产品,只有在老项目维护时可能出现的技术栈。

(5)Spring Boot + Spring Cloud。微服务架构项目常用组合。

(6)Spring Boot+Mybatis+MybatisPlus。新项目最先选择,比SSM组合使用起来更加方便。

(6)Spring Boot + Shiro/Spring Security。具有权限控制时的组合。

(7)SSM + Shiro/Spring Security。具有权限控制时的组合。

二、软件分层开发

1. Java EE 三层模型 和 MVC模型

Java EE 三层模型和MVC模型属于两种分层模型,一些同学可能认为这是同一个概念,其实并不然。

Java EE中最经典的是三层模型。包含表示层(Presentation)、业务逻辑层(Business Logic)、持久层(Persistence)

MVC 模型也是三层模型。包含模型层(Model)、视图层(View)、控制层(Controller)。

Java EE 三层模型和MVC模型最主要的区别是:

(1)Java EE三层模型中没有控制层,MVC中有控制层。

(2)Java EE三层模型中业务模型层是单独一部分,就是service层,MVC中模型层包含:业务模型(业务逻辑层)和数据模型(实体类,持久层)。

(3)Java EE三层模型中持久层就是dao层。MVC中虽然持久层在项目中是单独的包,但是在MVC概念中持久层属于模型层中。

2. 目前Java中最常见的六层模型

目前在软件开发过程中最常见的是六层模型,我们讲解的也是六层模型:

(1)视图层。简单点说就是页面,可以是客户端页面技术,也可以是服务端页面技术。例如:HTML、JSP。

(2)控制层。处于业务层和视图层之间,根据业务层结果,控制视图层显示。例如:Servlet。

(3)实体层。就是实体类,负责封装数据,在各个层之间进行数据传递的载体。常见包名:pojo、domain、entity等。

(4)业务逻辑层。专门编写业务逻辑代码。

(5)数据持久层/数据访问层。负责编写调用数据库的代码。具体技术:JDBC、MyBatis等。

(6)数据源层。一些持久化工具,负责存储数据的。例如:MySQL、Oracle等。

3. ORM

ORM(Object/Relation Mapping),中文名称:对象/关系 映射。是一种解决数据库发展和面向对象编程语言发展不匹配问题而出现的技术。

 使用JDBC技术时,手动实现ORM映射:

 ORM框架封装了对象/关系的自动映射。

6.常见的ORM框架

对于Java程序员来说,整个职业生涯可能听说过或可能用上的ORM框架:

(1)MyBatis:目前使用最多的ORM框架。

(2)Hibernate:零SQL的ORM框架,N年前使用最多的ORM框架。目前只能在一些老的项目中看到。

(3)Spring Data JPA:目前个别公司中使用的ORM框架。是Spring Data家族中的一员。是对JPA(Java Persistence API,JDK5.0)的封装。

(4)Spring Data JDBC:Spring Data中的二级项目,类似Spring Data JPA,但框架的功能要比Spring Data JPA少一些。

三、MyBatis介绍

1. 介绍

MyBatis 是一款优秀的ORM框架,MVC分层开发中的持久层框架,它支持自定义 SQL、存储过程以及高级映射。

四、第一个MyBatis项目

2. 创建Maven项目并添加依赖

创建一个Maven项目(示例中叫做:maven1),并配置pom.xml。

需要添加MyBatis的依赖和MySQL驱动的依赖。(文档制作时MyBatis最新版本为3.5.9,mysql驱动最新版本为8.0.29)因为MyBatis的底层也是MySQL,JDBC实现的

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.sh</groupId><artifactId>MyBatis01</artifactId><version>1.0-SNAPSHOT</version><dependencies><!-- MyBatis 框架依赖 --><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.28</version></dependency></dependencies></project>

3. 创建MyBatis全局配置文件

在项目的src/main/resources目录下新建mybatis.cfg.xml文件。并在配置文件中填写下面内容。

配置文件解释:

  1. XML文档头是XML文件必须有的。

  2. DOCTYPE声明文档类型,引入外部约束。

  3. <configuration>是根节点。

  4. <environments>的default属性取值必须是下面某个<environment>标签的id属性值。表示当前MyBatis框架到底使用哪个环境。

  5. <environment>的id值是自定义的。表示当前数据库环境的名称。在全局配置文件中<environment>标签可以有多个,里面分别配置上数据源相关参数。例如一个里面配置连接本地MySQL的参数,另一个配置连接服务器中MySQL的参数,还有一个配置连接Oracle数据库的相关参数。都准备好了以后可以通过修改<environments>中default的值来切换连接的数据库,这样要比修改里面具体的连接参数更加方便。

  6. <transactionManager>中type属性用于配置事务的类型。可取值:

    • JDBC:使用原生JDBC的事务管理进行提交和回滚。

    • MANAGED:MyBatis不参与事务管理。交给其他人管理事务。

  7. <dataSource>中type属性值用于配置数据源类型。可取值:

    • UNPOOLED:不使用数据库连接池。每次执行SQL都会打开数据库连接,执行SQL结束都会关闭连接。适用于简单小型应用。

    • POOLED:使用MyBatis内置数据库连接池。对于频繁访问数据库的应用程序来说,这个取值是很适合的。

    • JNDI:使用本地目录接口技术连接容器外部的数据源。这种方式很少使用,一般都是极其复杂的项目,对数据源要求极高的情况下才能使用。

  8. <properties>配置具体属性和值

    driver、url、username、password四个属性名称是固定的,但是没有顺序要求,添加到<properties>的name属性中即可。分别代表驱动类、连接字符串、用户名、密码。value属性的值为连接数据库的具体参数值。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!-- 配置执行的数据库环境 default中是默认使用哪个数据库技术--><!-- default中的名字也可以叫别的--><environments default="mysql"><environment id="mysql"><!--事务控制器有两种1. JDBC : 使用原生的JDBC的事务管理2. MANAGED : MyBatis不参与事务管理,交给其他人管理--><transactionManager type="JDBC"></transactionManager><!--配置数据源有三种UPOOLED: 不使用数据库连接池POOLED : 使用数据库连接池JNDI : 使用本地目录接口技术,特殊情况使用--><dataSource type="POOLED"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/ssm?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false&amp;serverTimezone=GMT%2B8&amp;allowPublicKeyRetrieval=true"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment></environments>
</configuration>

4. 创建Mapper映射文件

在src/main/resources目录中新建mybatis目录。这个文件夹可以新建也可以不建立,名称也是随意的。以后mapper文件会比较多,建立一个文件夹项目结构比较好看,名称叫做mybatis也好记。

在mybatis文件夹下新建xml文件,文件名称随意。示例中就叫做mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--  配置SQL映射的文件 -->
<mapper namespace="a.b"><insert id="addUser">insert into people values(default ,'zs','123')</insert>
</mapper>

5. 配置加载mapper映射文件

映射文件是不能默认被加载的。需要在全局配置文件mybatis.cfg.xml中手动指定加载路径。

6. 编写测试类,启动项目

package com.sh;import static org.junit.Assert.assertTrue;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 java.io.IOException;
import java.io.InputStream;/*** Unit test for simple App.*/
public class AppTest {/*** Rigorous Test :-)*/@Testpublic void test1() throws IOException {// 1. 获取全局配置文件输入流InputStream is = Resources.getResourceAsStream("mybatis.cfg.xml");// 2. 加载全局配置文件后创建工厂类SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);// 3. 使用工厂创建SqlSession. 里面封装了所有增删改查的方法SqlSession session = factory.openSession();// 4. 执行sql方法,里面传递 namespace.id 通过语句的唯一标识找到sql语句int index = session.insert("a.b.addUser");System.out.println(index);// 5. mybatis是手动提交session.commit();// 6. 关闭连接,释放资源session.close();}
}

五、MyBatis属性加载

MyBatis支持加载属性文件(.properties文件),可以通过在属性文件中配置数据库连接属性然后加载。这种方式要比直接写稍微麻烦一点点,但是却把所有的数据库连接书写到了统一的文件中,以后查看或修改时更加方便。

1. 创建属性文件

在src/main/resources目录中创建jdbc.properties文件

注意:需要将$amp;转义字符变为&,否则运行报错

jdbc.url=jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.username=root
jdbc.password=root

2. 修改全局配置文件

修改mybatis.cfg.xml文件,设置加载属性。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!-- 加载属性文件 ,再给属性赋值 --><properties resource="jdbc.properties"></properties><!-- 配置执行的数据库环境 default中是默认使用哪个数据库技术--><!-- default中的名字也可以叫别的--><environments default="mysql"><environment id="mysql"><!--事务控制器有两种1. JDBC : 使用原生的JDBC的事务管理2. MANAGED : MyBatis不参与事务管理,交给其他人管理--><transactionManager type="JDBC"></transactionManager><!--配置数据源有三种UPOOLED: 不使用数据库连接池POOLED : 使用数据库连接池JNDI : 使用本地目录接口技术,特殊情况使用--><!--<dataSource type="POOLED"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/ssm?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false&amp;serverTimezone=GMT%2B8&amp;allowPublicKeyRetrieval=true"/><property name="username" value="root"/><property name="password" value="root"/></dataSource>--><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><mappers><mapper resource="mybatis/mapper.xml"></mapper></mappers>
</configuration>

五、常见Java日志工具包

1. 日志介绍

日志是项目开发非常重要的一项。项目部署到服务器以后,并不能所有信息都通过控制台或命令窗口进行查看。把日志信息输入到文件中更有利于项目的维护。

Java项目的日志是可以输入到控制台、可以输入到文件中、甚至可以输入到某个数据源中。但是常用的还是控制台和文件。

在Java项目中常见的日志工具包:

  • Log4j:Apache推出的日志工具。于2012年5月发布1.2.17版本后停止更新。

  • Logback:属于Log4j的继承者。Spring Boot默认日志文件支持类型。

  • Log4j2:属于Log4j升级版,同时里面还包含了Logback的很多改进。

  • commons-logging:Apache早期基于门面(Facade)设计模式的日志包,提供了日志解构能力,按照顺序寻找当前项目日志接口实现,Log4j、JDK Log、SimpleLog。

  • Slf4j( Simple Logging Facade for Java ):目前使用非常多的门面日志。统一项目中日志。

  • JDK Logging:JDK自带的日志API。

2. JDK Logging

JDK Logging 是JDK自带的日志工具。存在于java.uti.logging包中。

日志的级别: OFF > SEVERE > WARNING > INFO > CONFIG > FINE > FINER > FINEST > ALL

注意:

1. 默认级别为INFO。

2. 只会显示该级别及该级别以上日志信息。

package com.sh;import java.io.IOException;
import java.util.logging.*;public class Demo {public static void main(String[] args) throws IOException {//参数通常设置为所在的类名Logger logger = Logger.getLogger("Demo");// 默认为INFO级别,同时设置当前和父处理器级别才能修改// OFF > SEVERE > WARNING > INFO > CONFIG > FINE > FINER > FINEST > ALLlogger.setLevel(Level.FINEST);Handler[] handlers = logger.getParent().getHandlers();// 获取输出控制台的处理器handlers[0].setLevel(Level.FINEST);// 设置控制台输出级别// 默认没有输出到文件,只输出到控制台,通过添加Handler增加输出目的地,输出到文件中FileHandler fh = new FileHandler("my.log");// 如果路径夹会不存在文件夹会报错fh.setFormatter(new SimpleFormatter());// 设置输出内容为普通格式logger.addHandler(fh);logger.severe("severe");// 严重logger.warning("warning");// 警告logger.info("info");// 信息logger.config("config");// 配置logger.fine("fine");// 详细logger.finer("finer");// 较详细logger.finest("finest");// 非常详细}
}

3. Log4j的使用

Log4j是Apache的开源日志工具。最新版本为2012年发布的1.2.17。

Log4j会自动寻找classpath下log4j.properties作为配置文件。

具体使用步骤:

3.1 配置pom.xml
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>
3.2 编写配置文件

在resources中新建log4j.properties,名称不要写错了。

log4j中定义的级别:fatal(致命错误) > error(错误) > warn(警告) > info(普通信息) > debug(调试信息) > trace(跟踪信息)

# log4j中定义的级别:fatal(致命错误) > error(错误) > warn(警告) > info(普通信息) > debug(调试信息) > trace(跟踪信息)
# 跟日志等级为debug 使用console和file两种方式输出
log4j.rootLogger = DEBUG , console , file### console ###(日志显示在控制台的配置)
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = [%p] [%-d{yyyy-MM-dd HH\:mm\:ss}] %C.%M(%L) | %m%n### log file ###(日志输出在文件中的配置)
log4j.appender.file = org.apache.log4j.DailyRollingFileAppender
# 日志输出的路径
log4j.appender.file.File = log4j.log
# 是否给日志文件追加
log4j.appender.file.Append = true
# 级别只能比根日志界别高,比根日志级别低不生效
#log4j.appender.file.Threshold = info
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = [%p] [%-d{yyyy-MM-dd HH\:mm\:ss}] %C.%M(%L) | %m%n
3.3 编写测试类

注意:千万不要倒错包。

package com.sh;
// 不要导错包
import org.apache.log4j.Logger;public class TestLog4j {public static void main(String[] args) {Logger logger = Logger.getLogger(TestLog4j.class);logger.trace("跟踪级别");logger.debug("调试信息");logger.info("普通信息");logger.warn("警告信息");logger.error("错误信息");logger.fatal("重大错误信息");}
}

4. Log4j2

4.1 配置pom.xml

虽然只导入了log4j-core,但是实际导入log4j-core和log4j-api。

<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.17.2</version>
</dependency>
4.2 编写配置文件

Log4j2不再支持Log4j的.properties格式配置文件。而是支持.xml、.json、jsn。

Log4j2中定义的级别:fatal(致命错误) > error(错误) > warn(警告) > info(普通信息) > debug(调试信息) > trace(跟踪信息)

在resource目录新建log4j2.xml。

<?xml version="1.0" encoding="utf-8" ?>
<Configuration ><!-- 定义输出的目的地 --><Appenders><!-- Console 定义控制台输出 name:自定义名称 target:输出方式,支持SYSTEM_OUT SYSTEM_ERR --><!-- SYSTEM_OUT 正常输出内容SYSTEM_ERR 错误高亮输出内容--><Console name="console" target="SYSTEM_OUT"><!-- 输出信息表达式 --><PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/></Console><!-- File 定义文件输出 fileName 文件路径  append是否允许追加 --><File name="file" fileName="log4j2.log" append="true"><PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/></File></Appenders><Loggers><!-- 控制总体级别 --><!-- fatal > error > warn > info > debug > trace --><Root level="info"><!-- 引用输出位置的配置,Appenders中直接子标签的name属性值 --><!-- 映射哪种输出模式 --><AppenderRef ref="console"/><AppenderRef ref="file"/></Root></Loggers>
</Configuration>
4.3 编写测试类
package com.bjsxt;
// 千万别导错包了
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;public class TestLog4j {public static void main(String[] args) {Logger logger = LogManager.getLogger(TestLog4j.class);logger.trace("跟踪级别");logger.debug("调试信息");logger.info("普通信息");logger.warn("警告信息");logger.error("错误信息");logger.fatal("重大错误信息");}
}

5. SLF4j

SLF4j是日志的接口声明,不参与日志的具体实现,需要配合其它日志具体实现工具包才能进行使用。

每次添加其它日志工具包时,不要忘记SLF4j整合这个日志的依赖。

5.1 整合Log4j
5.1.1 导入依赖

导入3个依赖,分别代表slf4j依赖、整合依赖、log4j的依赖。

<!--slf4j整合log4j的依赖,版本要和slf4j的版本对应 -->
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.36</version>
</dependency>
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>
5.1.2 编写log4j的配置文件

使用写号的log4j.properties文件就行

5.1.3 编写测试类

小提示:

SLF4J作为门面设计模式的具体实现,无论使用哪种日志具体实现,都是下面的API。

public class TestSlf4j {public static void main(String[] args) {Logger logger = LoggerFactory.getLogger(TestSlf4j.class);logger.trace("trace");logger.debug("debug");logger.info("info");logger.warn("warn");logger.error("error");}
}
5.2 整合Log4j2
5.2.1 配置pom.xml

与SLF4J整合Log4j的整合包是不一样的。

<dependencies><!-- SLF4j整合Log4j2的依赖 --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><version>2.17.2</version></dependency><!-- Log4j2工具的依赖--><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.17.2</version></dependency>
</dependencies>
5.2.2 添加Log4j2的配置文件

使用之前的log4j2.xml文件。

5.2.3 运行测试类

测试类的API和整合Log4j的API是完全相同的,直接运行即可。

5.3 即整合Log4j又整合Log4j2

SLF4J支持多种日志实现,但是在项目中整合依赖最好只有一个,否则会出现警告。

六、MyBatis启用日志功能

1. MyBatis支持的日志

MyBatis框架内置日志工厂。日志工厂负责自动加载项目中配置的日志。MyBatis支持以下日志,当存在多个日志工具时,严格按照从上往下顺序使用,且只会使用一个。

  • SLF4J

  • Apache Commons Logging

  • Log4j 2

  • Log4j (deprecated since 3.5.9)

  • JDK logging

2. MyBatis结合Log4j实现打印执行的SQL

3. MyBatis结合Log4j2实现打印执行SQL

同理演示Log4j2

3.1 编写pom.xml,引入依赖
<dependencies><!-- MyBatis 框架依赖 --><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.28</version></dependency><!-- log4j2 --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.17.2</version></dependency>
</dependencies>
3.2 创建配置文件

在resources目录下新建log4j2.xml文件

<?xml version="1.0" encoding="utf-8" ?>
<Configuration ><Appenders><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/></Console></Appenders><Loggers><Root level="info"><AppenderRef ref="Console"/></Root><!-- namespace的值 --><logger name="a.b" level="debug"></logger></Loggers>
</Configuration>

4. 指定生效的日志

在MyBatis中默认按照顺序寻找,如果项目中存在多个日志。可以通过mybatis全局配置文件进行设置哪个日志生效。

在mybatis.cfg.xml中配置<settings>的标签

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><properties resource="jdbc.properties"></properties><!-- 配置哪个日志生效 , 多个日志的时候设置 --><!--<settings><setting name="log4j2" value="LOG4J2"/></settings>--><!-- 配置执行的数据库环境 default中是默认使用哪个数据库技术--><!-- default中的名字也可以叫别的--><environments default="mysql"><environment id="mysql"><!--事务控制器有两种1. JDBC : 使用原生的JDBC的事务管理2. MANAGED : MyBatis不参与事务管理,交给其他人管理--><transactionManager type="JDBC"></transactionManager><!--配置数据源有三种UPOOLED: 不使用数据库连接池POOLED : 使用数据库连接池JNDI : 使用本地目录接口技术,特殊情况使用--><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}"/><property name="url"value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><mappers><mapper resource="mapper.xml"></mapper></mappers>
</configuration>

5. 测试

package com.sh;import static org.junit.Assert.assertTrue;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 java.io.IOException;
import java.io.InputStream;/*** Unit test for simple App.*/
public class AppTest {/*** Rigorous Test :-)*/@Testpublic void test1() throws IOException {//1.通过流读取全局配置文件InputStream is = Resources.getResourceAsStream("mybatis_config.xml");//2.创建工厂SqlSessionFactory构建器然后创建工厂SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);//3.通过工厂创建SqlSessionSqlSession session = factory.openSession();//4.session中封装了所有的增删改查的方法int i = session.insert("a.b.add1");//验证结果System.out.println(i);//5. 增删改手动提交事务session.commit();//6. 释放资源session.close();}
}

七、SQL参数

1. MyBatis中的占位符

MyBatis中最常用的占位符为 #{},在MyBatis的mapper文件的SQL中使用#{}作为占位符。最终解析时会解析成JDBC的占位符?。

2. 当参数为简单数据类型

当参数为一个简答数据类型时。例如:八大基本数据类型、String类型等。可以通过#{任意内容}获取到。

小提示:

1. 任意内容代表着,随意写,只要不是特殊字符即可。

2. 但是要注意不能不写。

2.1 修改Test类

SqlSession的insert()方法有两种。

想要传递参数就需要使用insert(String,Object)的方法。

 @Testpublic void test2(){SqlSessionFactory factory = getFactory();//3.通过工厂创建SqlSessionSqlSession session = factory.openSession();int i = session.insert("a.b.add2","456");System.out.println(i);session.commit();session.close();}
 <insert id="add2">insert into user values (default ,'ls',#{pwd})</insert>

通过使用,使用#{} 给占位赋值  先将#{}变成? 再进行解析 只有一个值需要赋值时

#{}括号中写什么都行

3. 当参数为多个值时 

3.1 修改Test类

由于insert(String,Object)方法只有一个Object类型方法能作为SQL参数,如果希望传递多个值,有两种选择:

1.可以创建一个对应类,通过对象进行传递。

参数是对象通过${属性名}获取

 @Testpublic void test3(){SqlSessionFactory factory = getFactory();//3.通过工厂创建SqlSessionSqlSession session = factory.openSession();User user = new User();user.setUsername("zw");user.setPassword("789");int i = session.insert("a.b.add3",user);System.out.println(i);session.commit();session.close();}

2.也可以把所有SQL参数放入到一个Map中。

参数是Map,通过${key}获取

@Testpublic void test3(){SqlSessionFactory factory = getFactory();//3.通过工厂创建SqlSessionSqlSession session = factory.openSession();/* User user = new User();user.setUsername("zw");user.setPassword("789");*/HashMap<String, String> map = new HashMap<>();map.put("username","zw");map.put("password","147");int i = session.insert("a.b.add3",map);System.out.println(i);session.commit();session.close();}
3.2 mapper文件
 <insert id="add3">insert into user values (default ,#{username},#{password})</insert>

4. ${} 的使用

在MyBatis中还有一种占位符写法:${}。

${}在被MyBatis进行解析时,不会解析为占位符?,而是直接解析成对应的,类似字符串拼接

学习JDBC时我们知道SQL中存在字符串拼接时,会有SQL注入问题。

那是不是意味着${}没有使用场景了?答案是否定的。JDBC中占位符?是不允许代替列名和表名的,也就意味着MyBatis的#{}不允许代替表名和列名但是使用${}可以动态设置列名或表名。

${}和#{}获取参数的写法完全相同。如果参数是对象通过${属性名}获取。如果参数是Map,通过${key}获取。如果参数是简单数据类型,通过${任意不为空的内容}进行获取。

4.1 修改映射文件

${}和#{}可以混合使用。实例中使用${}代替表名。

<insert id="add4">insert into ${table} values (default ,#{username},#{password})</insert>
4.2 修改Test类
 @Testpublic void test4(){SqlSessionFactory factory = getFactory();SqlSession session = factory.openSession();HashMap<String, String> map = new HashMap<>();map.put("table","user");map.put("username","zw");map.put("password","258");int i = session.insert("a.b.add4", map);System.out.println(i);session.commit();session.close();}

通过日志可以看到

${}直接解析为值  ,  而#{}则被解析为?

八、MyBatis中修改和删除实现

1. 修改和删除功能总体说明

MyBatis实现修改和删除功能与实现新增时是非常类型的,SQL参数传递的几种方式也是相同的。

主要区别:

就是mapper文件中标签名不同。

SqlSession的方法名不同。

操作mapper标签SqlSession方法名
新增<insert>insert(String)、insert(String,Object)
修改<update>update(String)、update(String,Object)
删除<delete>delete(String)、delete(String,Object)

2. 修改实现

2.1 修改映射文件

修改suiyi.xml文件.在里面添加上<update>标签。设定使用Map进行传递参数了,所以直接使用#{key}获取到参数。

 <update id="update1">update user set username=#{username} where id=#{id}</update>
2.2 修改测试类
 @Testpublic void test5(){SqlSessionFactory factory = getFactory();SqlSession session = factory.openSession();HashMap<String, String> map = new HashMap<>();map.put("username","hhh");map.put("id","1");int i = session.update("a.b.update1", map);System.out.println(i);session.commit();session.close();}

3. 删除实现

3.1 修改映射文件

修改suiyi.xml文件.在里面添加上<delete>标签。设定使用Map进行传递参数了,所以直接使用#{key}获取到参数。

 <delete id="delete1">delete from user where id=#{id}</delete>
3.2 修改测试类
/* 删除实现 */@Testpublic void test6(){SqlSessionFactory factory = getFactory();SqlSession session = factory.openSession();int i = session.delete("a.b.delete1", 10);System.out.println(i);session.commit();session.close();}

九、MyBatis中DQL操作

MyBatis的DQL操作在映射文件都是通过<select>标签实现的。

SqlSession根据根据查询结果类型不同,提供了五种查询方法:

方法名解释说明
selectOne()查询一行数据时,返回值为Object。如果没有查询到,但是不能查询到多行。
selectMap()查询多行数据时,把其中某列结果当做key,每行结果为Value
selectList()当查询多行数据时,返回值为List。如果没有查询到返回长度为零的List对象。
selectCursor()使用游标查询时使用,在大量数据时可以代替分页
select()万能方法,需要自己定义结果处理器

2. selectOne()方法使用

selectOne()方法要求查询结果是一行或没有查询到。如果查询结果是多行会报异常。

如果这行数据有多个值,可以放在实体类对象中。如果这行数据只有一列,可以使用简单数据类型接收

2.1 查询到一行或没有查询到结果时
2.1.1 修改映射文件

在映射中添加<select>标签,resultType属性是<select>标签必须有的属性,表示查询结果最终类型。取值为类型的全限定路径。就是查询结果对应的类是哪个要指定,而且要使用包名+类名

<!--DQL:selectOne必须保证列名和resultType中类型的属性名相同才能保证把查询到的结果自动放入对象当中
--><select id="one" resultType="com.sh.util.User">select * from user where id = #{id}</select>
2.1.2 修改Test类

selectOne()方法返回值是泛型类型,所以可以直接写对应的类型。

@Testpublic void test7(){SqlSessionFactory factory = getFactory();SqlSession session = factory.openSession();Map<String,Object> map = new HashMap<>();map.put("id",1);// 使用selectOne方法进行查询// 返回值可以直接写映射文件中select的resultType对应类型//知道是user类型直接转换成user类型User user = session.selectOne("a.b.select1", map);System.out.println(user);//查询不需要事务的提交/*session.commit();*///释放资源session.close();}
2.1.3 当没有写resultType属性时

resultType是<select>必须写的属性。如果不写resultType属性执行时会报错。在示例中删除掉了resultType属性。

2.1.4 查询到多行数据时

如果使用selectOne()方法,对应的SQL查询到多行数据会报错。

例如:修改映射文件的SQL为查询全部,且保证数据库people表有2行以上数据

3. selectList()方法使用

selectList()方法主要用在多行查询时,查询时把每行结果按照resultType类型进行封装,最终放入到List中。

3.1 修改映射文件

注意:resultType的类型为每行结果的类型,也就是List的泛型的类型。

<select id="select2" resultType="com.sh.util.User">select * from user</select>
3.2 修改Test类
//查询多个@Testpublic void test8(){SqlSessionFactory factory = getFactory();SqlSession session = factory.openSession();// 使用selectList方法进行查询// 返回值可以直接写映射文件中select的resultType对应类型List<User> list = session.selectList("a.b.select2");System.out.println(list);//查询不需要事务的提交/*session.commit();*///释放资源session.close();}

4. selectMap()方法使用

selectMap(String statement,Object param,String key);比上面多了String key参数。

String key:指定查询结果中哪列的值作为map的key。map的value是整行数据,类型和resultType类型一致。

4.1 修改映射文件
<select id="select3" resultType="com.sh.util.User">select * from user</select>
4.2 修改测试类

修改后运行效果,查看key和value的值

 // 使用 selectMap()@Testpublic void test9(){SqlSessionFactory factory = getFactory();SqlSession session = factory.openSession();// 使用selectList方法进行查询// 返回值可以直接写映射文件中select的resultType对应类型Map<String, Object> map = session.selectMap("a.b.select3", "id");System.out.println(map);//查询不需要事务的提交/*session.commit();*///释放资源session.close();}

5. selectCursor()方法使用

cursor 表示游标。属于对查询结果集的一种遍历方式。MyBatis底层使用JDBC,在MyBatis封装的Cursor中只有遍历功能。其实就是一个一个的查询出来

5.1 修改映射文件
 <select id="select4" resultType="com.sh.util.User">select * from user</select>
5.2 修改Test类

selectCursor()返回值为Cursor,提供了forEach()遍历和iterator()两种遍历方式,下面使用forEach()遍历方式。

@Testpublic void test10(){SqlSessionFactory factory = getFactory();SqlSession session = factory.openSession();// 使用selectList方法进行查询// 返回值可以直接写映射文件中select的resultType对应类型//泛型知道是userCursor<User> cursor = session.selectCursor("a.b.select4");cursor.forEach(System.out::println);//查询不需要事务的提交/*session.commit();*///释放资源session.close();}

6. select()方法使用

select(String statement,Object param,ResultHandler resultHandler);方法中第三个参数表示结果处理。

在ResultHandler接口中只有一个方法,表示如何处理

//使用select//自定义查询@Testpublic void test11(){SqlSessionFactory factory = getFactory();SqlSession session = factory.openSession();// 使用selectList方法进行查询// 返回值可以直接写映射文件中select的resultType对应类型//该方法是自定义查询,需要重写handleResult方法,可以创建一个类继承ResultHandle来实现//也可以使用匿名内部类,这里使用内部类MyResultHandler myResultHandler = new MyResultHandler();session.select("a.b.select5",myResultHandler);//查询不需要事务的提交/*session.commit();*/System.out.println("-------------------");System.out.println(myResultHandler.getResult());//释放资源session.close();}public class MyResultHandler implements ResultHandler {HashSet<Object> set = new HashSet<>();@Overridepublic void handleResult(ResultContext resultContext) {// System.out.println(resultContext.getResultObject());set.add(resultContext.getResultObject());}public Set<Object> getResult(){return set;}}

十、分页查询

1. MyBatis实现分页查询的几种方式

在MyBatis中实现查询有两种方式:

  1. 根据对应的数据库,编写SQL。这种方式与数据库耦合度较高,移植性差。但是确实我们平时使用的方式,因为大部分项目是没有修改数据库类型的场景。

  2. 使用MyBatis提供的RowBounds实现分页

2. 根据对应数据库编写SQL

2.1 修改映射文件
<select id="select6" resultType="com.sh.util.User">select * from user limit #{index},#{size}</select>
2.2 修改测试类
@Testpublic void test12(){SqlSessionFactory factory = getFactory();SqlSession session = factory.openSession();HashMap<String, Object> map = new HashMap<>();map.put("index",0);map.put("size",3);session.selectList("a.b.select6",map);System.out.println(map);//释放资源session.close();}

这是类似JDBC的方法

3. RowBounds方式进行分页

RowBounds是MyBatis中提供的一种"假分页"实现方式。对从数据库中查询到的结果进行截取。所以如果数据库中数据量特别大的时候可能会出现OOM等问题。就是当查询第二页时会把第一页的数据也查询出来,但是最终只截取第二页的内容

但是由于RowBounds不需要考虑底层数据库是什么,且使用简单,所以对于一些数据量不是特别大的应用还是有人选择使用的。

在SqlSession中select、selectMap、selectList中通过方法重载都提供了一个带有RowBounds。

3.1 修改映射文件
<!-- 使用RowBounds --><select id="select7" resultType="com.sh.util.User">select * from user</select>
3.2 修改Test类
/* 使用RowBounds */@Testpublic void test13(){SqlSessionFactory factory = getFactory();SqlSession session = factory.openSession();//创建偏移量对象RowBounds rowBounds = new RowBounds(0, 3);//因为偏移量必须是第三个参数,再不需要给占位符赋值的时候,第二个参数也必须要写,写为nullList<User> list = session.selectList("a.b.select7", null, rowBounds);System.out.println(list);//释放资源session.close();}

十一、模糊查询

1. 使用#{}实现模糊查询

1.1 修改映射文件
<select id="select8" resultType="com.sh.util.User">select * from user where username like #{username}</select>
1.2 修改测试类
// 模糊查询@Testpublic void test14(){SqlSessionFactory factory = getFactory();SqlSession session = factory.openSession();List<User> list = session.selectList("a.b.select8","%s%");System.out.println(list);//释放资源session.close();}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/154761.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Colab matplotlib画图如何显示中文字体【图例坐标轴均可显示中文】

Colab notebook用matplotlib画图中文出现方块&#xff1a; 如何解决这个问题呢&#xff1f; 运行wget -O simhei.ttf "https://www.wfonts.com/download/data/2014/06/01/simhei/chinese.simhei.ttf"&#xff0c;安装中文字体&#xff0c;这里装得是SimHei&#xf…

电脑上播放4K视频需要具备哪些条件?

在电视上播放 4K&#xff08; 4096 2160 像素&#xff09;视频是很简单的&#xff0c;但在电脑设备上播放 4K 视频并不容易。相反&#xff0c;它们有自己必须满足的硬件要求。 如果不满足要求&#xff0c;在电脑上打开 4K 分辨率文件或大型视频文件会导致卡顿、音频滞后以及更…

uniapp-vue3微信小程序实现全局分享

uniapp-vue3微信小程序实现全局分享 文章目录 uniapp-vue3微信小程序实现全局分享微信小程序官方文档的分享说明onShareAppMessage(Object object)onShareTimeline() uniapp 官方文档的分享说明onShareAppMessage(OBJECT) 实现全局分享代码结构如下share.js文件内容main.js注意…

Pushgateway的场景使用

1,Pushgateway简介 Pushgateway为Prometheus整体监控方案的功能组件之一,并做为一个独立的工具存在。它主要用于Prometheus无法直接拿到监控指标的场景,如监控源位于防火墙之后,Prometheus无法穿透防火墙;目标服务没有可抓取监控数据的端点等多种情况。在类似场景中,可通…

串口硬件流控RTS、CTS

为什么有时候要在RXD和TXD的基础上增加RTS、CTS&#xff1f; 当接收端的串口处理速度过低时&#xff0c;会丢失数据&#xff0c;因此考虑增加一种通知的机制来告诉发送端是否可以发送&#xff0c;即增加了RTS&#xff08;Require To Send&#xff09;和CTS&#xff08;Clear T…

用“和美”丈量中国丨走进酒博物馆系列⑨

五粮液酒文化博览馆始建于1988年&#xff0c;是中国酒业最早的酒文化博览馆&#xff0c;于2020年启动升级改造。 现在我们看到的五粮液酒文化博览馆&#xff0c;采用了当今博览馆最前沿的展陈方式&#xff0c;展陈设计与空间布局更具灵动性和多元性&#xff0c;蕴含传统文化氛围…

stable diffusion艰难炼丹之路

文章目录 概要autoDL系统盘爆满autoDL python3.8切换python3.10dreambooth训练大模型完成后报错 概要 主要是通过autoDL服务器部署stable diffusion&#xff0c;通过dreambooth训练大模型。 问题&#xff1a; autoDL系统盘爆满autoDL python3.8切换python3.10dreambooth训练大…

mac M2芯片在使用Android studio 编译问题bad cpu type in executable android

由于mac的intel芯片的一些指令集没有同步在M1 M2芯片上所以需要做兼容 打开控制台&#xff08;通过访达 - 应用程序 - 实用工具 - 终端 &#xff09; 输入 softwareupdate --install-rosetta 之后在输入 A 就可以了。 原产考地址&#xff1a;硬核&#xff01;在 M1 芯…

智能视频监控,究竟“智”在哪里?

当人们一提到智能视频监控时&#xff0c;就会想起高清摄像头、人脸识别等技术。其实不然&#xff0c;真正智能视频监控不仅仅是这些技术算法&#xff0c;更重要的是如何将这些算法融入到应用场景中&#xff0c;更好地去服务大众、起到降本增效的作用。 首先&#xff0c;智能视…

塔望食观察 | 中国海参产业发展现状及挑战

海参&#xff0c;一个古老的物种&#xff0c;堪称海底活化石&#xff0c;据资料显示&#xff0c;海参在地球上存活超过6亿年&#xff0c;比恐龙还早。海参的药用、食疗和营养滋补价值极高&#xff0c;清朝学者赵学敏编的《本草纲目拾遗》有这样的叙述&#xff1a;“海参性温补&…

踩雷react-useRef钩子函数

今天测试提了一个bug&#xff0c;之前做的有个需求&#xff0c;在触发事件发起请求后&#xff0c;成功响应返回的新的数据没有第一时间渲染到网页上。 方法也都成功更新了数据&#xff0c;就是渲染会慢1-2分钟&#xff0c;排错排了老半天&#xff0c;最后找到了原因。 一般情…

Qt如何实现动态背景-视频背景

前言 需求&#xff1a;加载视频作为视频背景&#xff0c;在上层可以进行图片的动画化&#xff0c;或是进行其他操作。 几种方法&#xff1a; 1、直接将视频弄成一个QDialog&#xff0c; 然后再上层在弄一个QDialog,背景透明即可。但遇到一个问题&#xff0c;QDialog没办法局…

物业一站式工单管理系统哪家好?如何提升物业管理和维修服务质量?

在物业管理和维修服务领域&#xff0c;一个高效便捷的工单管理系统扮演着至关重要的角色。它不仅方便了住户提交报修请求&#xff0c;还极大地提高了物业管理和维修团队的工作效率。本文将深入探讨“的修”一站式工单管理系统在物业管理和维修服务中的重要作用。 一、“的修”一…

一款轻量级事件驱动型应用程序框架

QP™/C 实时嵌入式框架 &#xff08;RTEF&#xff09; 是专为实时嵌入式 &#xff08;RTE&#xff09; 系统量身定制的活动对象计算模型的轻量级实现。QP 既是用于构建由活动对象&#xff08;参与者&#xff09;组成的应用程序的软件基础结构&#xff0c;也是用于以确定性方式执…

linux安装filebeat并收集日志到elasticsearch

摘要&#xff1a; 通过filebeat收集服务器上各个应用的日志到elasticsearch&#xff0c;通过tags区分不同的应用创建不同的索引保存日志。 官网地址&#xff1a; https://www.elastic.co/cn/downloads/past-releases#filebeat 安装步骤&#xff1a; 1&#xff1a;下载并解…

C#(Csharp)我的基础教程(四)(我的菜鸟教程笔记)-Windows项目结构分析、UI设计和综合事件应用的探究与学习

目录 windows项目是我们.NET学习一开始必备的内容。 1、窗体类&#xff08;主代码文件窗体设计器后台代码文件&#xff09; 主窗体对象的创建&#xff1a;在Program类里面&#xff1a; Application.Run(new FrmMain());这句代码就决定了&#xff0c;当前窗体是项目的主窗体。…

MySQL 主从复制、读写分离

MySQL 主从复制、读写分离 1、MySQL 主从复制1.1什么是主从复制&#xff1f;1.2为什么要读写分离呢&#xff1f;1.3 什么时候要读写分离&#xff1f;1.4主从复制与读写分离1.5mysql支持的复制类型1.6主从复制的工作过程1.7MySQL 读写分离原理1.8目前较为常见的 MySQL 读写分离分…

2023年9月榜单丨飞瓜数据B站UP主排行榜(B站平台)发布!

飞瓜轻数发布2023年9月飞瓜数据UP主排行榜&#xff08;B站平台&#xff09;&#xff0c;通过充电数、涨粉数、成长指数、带货数据等维度来体现UP主账号成长的情况&#xff0c;为用户提供B站号综合价值的数据参考&#xff0c;根据UP主成长情况用户能够快速找到运营能力强的B站UP…

微信怎样批量添加好友?批量添加好友的好处有哪些?

微信是目前最流行的社交软件之一&#xff0c;不仅可以与亲友保持联系&#xff0c;还能为企业提供更多商机和合作伙伴。为了提高工作效率和增加客户数量&#xff0c;许多企业开始寻找批量自动化添加好友的工具。 那么批量添加好友的好处有哪些呢&#xff1f; ①批量自动化添加好…

微信小程序之本地生活(九宫格)

文章目录 一.创建项目二.配置修改json三.编写WXML四.编写WXSS五.最终效果 一.创建项目 创建新的项目&#xff0c;名称为&#xff1a;本地生活 二.配置修改json 在app.json中删除其他页面 将index改为grid 自动生成新的文件 添加自己的轮播图片 源代码&#xff1a; <!--…