一、整合MyBatis
a. 引入依赖:
<!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.18</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
b. 在 mybatis 中有个约定,需要配置 mapper 文件所在的路径,在 application.yml 文件中提供数据源
spring
datasource:
url: jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
druid:
initial-size: 1
min-idle: 1
max-active: 20
test-on-borrow: true
stat-view-servlet:
allow: true
mybatis:
mapper-locations:
- classpath*:mapper/**/*.xml
mapper-locations 指定配置文件所在的位置, 约定好mybatis的配置文件放在resources下的mapper包中
- classpath*:mapper/**/*.xml----------mapper-locations是一个String类型的数组, 因为参数类型不同,所以在每个参数前面加上一个 “-”。
注:在springboot中,默认会将application.yml文件中的datasource交给MyBatis去做,所以在mybatis中不需要指定datasource了。
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>
<!-- 获取数据源 -->
<properties resource="jdbc.properties"></properties>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!-- 开启懒加载功能 -->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
<setting name="cacheEnabled" value="true"/>
</settings>
<environments default="default">
<environment id="default">
<transactionManager type="JDBC"></transactionManager>
<!-- 用mybatis默认数据库连接池DBCP -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!-- 将(从配置)写好的SQL语句引入 -->
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
<mapper resource="mapper/OrderMapper.xml"/>
</mappers>
</configuration>
完了之后,我们要对mybatis开启接口扫描:直接在主类上面加上注解
@MapperScan(basePackages = { "com.example.demo.mapper" })
mybatis从配置
a) 在 mybatis 从配置 UserMapper.xml 的sql语句中 ${} 和 #{} 的区别:
#{}:会根据传入参数类型进行插入,如果是String,则自动加上单引号;
${}:直接引入,不做任何修改,如果在单引号中使用占位符(一般只在模糊查询中使用),只能用$符,且如果引用的参数类型是八大基本类型和String,那么占位符内的变量名只能为value;
测试类:
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class Test{
@Test
public void test(){
String resources = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream(resources);
// sqlSessionFactory : mybatis容器
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
/*等价于:SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().
build(Resources.getResourceAsStream("mybatis-config.xml"));*/
User user = new User();
user.setUsername(username);
user.setPassword(password);
SqlSession session = sqlSessionFactory.openSession();
User user1 = session.selectOne("userMapper.update",user);
session.summit();
session.close();
}
}
注:mybatis中进行增删改,需要提交事务才会从事务缓存同步到数据库
session.commit();
session.close();
Mapper的代理类实现
当 UserMapper.java接口中的【方法名,参数】与 UserMapper.xml中的 id 和 parameterType 相对应,mybatis会根据 UserMapper.class 接口和UserMapper.xml 中的 namespace(命名空间) 和 封装标签的逻辑(sql语句)以及 id 的匹配,对接口中的所有方法生成一个代理类,在真正使用时用的是代理类
public class Test{
@Test
public void querryAllUser(){
String resources = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream(resources);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession session = sqlSessionFactory.openSession();
//代理类实现
UserMapper userMapper = session.getMapper(UserMapper.class);
//匹配 UserMapper.xml 中id为querryAllUser的select标签
List<User> users = userMapper.querryAllUser();
for(User user : users){
syso(user);
}
session.summit();
session.close();
}
}
如何在mybatis中使用uuid:
<insert id="insertUUID" parameterType="net.xikee.spring.demo.pojo.UUID">
<selectKey order="BEFORE" resultType="string" keyProperty="uuid">
select uuid()
</selectKey>
insert into t_uuid(uuid, mark) values(#{uuid}, #{mark})
</insert>
- order=“BEFORE” 表示在下面的sql 语句执行前执行;
- keyProperty=“uuid” 表示UUID 这个类中传进来的变量名(字段)为uuid,将从数据库中生成返回的 UUID 的值存到 uuid 中,此时UUID这个类中的属性 uuid 就有值了;
注:PostgreSQL方式生成UUID,见PostgreSQL详解文章
https://blog.csdn.net/xikee_Lee/article/details/100940103
mybatis的动态SQL
- 动态sql:mybatis核心对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接、组装。
- 好处:一条SQL语句可以将全部情况写完;
IF标签拼装:
a) po中有如下类:
public class UserQueryVo{
private User user; // id, username, password
private String money;
}
b) 在 UserMapper.xml 中写动态 sql :
<select id="queryUser" parameterType="net.xikee.pojo.UserQueryVo">
select * from user
<where>
<if test="user!=null">
<if test="user.id!=null and user.id!=' ' ">
and id = #{id}
</if>
<if test="user.username != null and user.username !=' ' ">
and username = #{user.username}
</if>
</if>
</where>
</select>
如果user对象为空,则 sql 语句为
// 所有条件不符,则where标签不会拼上去
select * from user
如果 id 和 username 都不为空,则为
// where 标签,会自动将第一个条件前的 and 去掉
select * from user where id = #{id} and username = #{user.username}
//set 标签,自动去掉最后一个逗号
update user set username=#{username}, password=#{password}
使用 sql 片段
将上边实现的动态sql判断代码块抽取出来,组成一个sql片段。其它的statement中就可以引用sql片段。方便程序员进行开发。
<!--动态sql片段
id:sql片段唯一标识
基于单表来定义sql片段,这样的话这个sql片段可重用性才高,在sql片段可重用性才高
在sql片段不要包括where
-->
<sql id="qusery_user_where">
<if test="user!=null">
<if test="user.id!=null and user.id!=' ' ">
and id = #{id}
</if>
<if test="user.username != null and user.username !=' ' ">
and username = #{user.username}
</if>
</if>
</sql>
<select id="findUserByinfo" parameterType="entity.UserQuerVo" resultType="entity.UserCustom">
SELECT * FROM user
<where>
<!--sql片段引用-->
<include refid="qusery_user_where"></include>
</where>
foreach 标签
输入多个 id 进行查询时 (select * from user where id in(1,2,4,5,7,6);),
向sql传递数组或List,mybatis使用foreach解析
<!--输入list集合 foreach遍历-->
<select id="findUserList" parameterType="entity.UserQuerVo" resultType="entity.UserCustom">
SELECT * FROM user WHERE
<!--collection:传入的集合的变量名称
item:每次循环将循环出的数据放入这个变量中(每一个循环的对象)
open:开始遍历时拼接串
close:结束遍历时拼接串
separator:遍历两个对象之间需要拼接的串(分隔)
-->
<foreach collection="ids" item="id" open="(" close=")" separator=",">
<!--每次遍历需要拼接的串-->
id = #{id}
</foreach>
</select>
switch语句
<choose> //switch
<when test=""></when> //case
<when test=""></when>
<otherwise></otherwise> //default
</choose>
log 日志输出
log4j定义了8个级别的log,优先级从高到低依次为:
OFF、FATAL、ERROR、WARN、INFO、DEBUG、TRACE、 ALL。
a) ALL 最低等级的,用于打开所有日志记录。
b) TRACE designates finer-grained informational events than the DEBUG.Since:1.2.12,很低的日志级别,一般不会使用。
c) DEBUG 指出细粒度信息事件对调试应用程序是非常有帮助的,主要用于开发过程中打印一些运行信息。
d) INFO 消息在粗粒度级别上突出强调应用程序的运行过程。打印一些你感兴趣的或者重要的信息,这个可以用于生产环境中输出程序运行的一些重要信息,但是不能滥用,避免打印过多的日志。
e) WARN 表明会出现潜在错误的情形,有些信息不是错误信息,但是也要给程序员的一些提示。
f) ERROR 指出虽然发生错误事件,但仍然不影响系统的继续运行。打印错误和异常信息,如果不想输出太多的日志,可以使用这个级别。
g) FATAL 指出每个严重的错误事件将会导致应用程序的退出。这个级别比较高了。重大错误,这种级别你可以直接停止程序了。
h) OFF 最高等级的,用于关闭所有日志记录。
步骤一:log4j.properties 配置
### \u8BBE\u7F6E###
//以info级别输出(会将info以及更高级别的日志分别输出到以下stdout,D,E变量配置的三个地方)
log4j.rootLogger = info,stdout,D,E
//输出到控制台
### \u8F93\u51FA\u4FE1\u606F\u5230\u63A7\u5236\u62AC ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
//“./” 表示同级目录 输出到同级目录的 logs/log.log中
### \u8F93\u51FADEBUG \u7EA7\u522B\u4EE5\u4E0A\u7684\u65E5\u5FD7\u5230=E://logs/error.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = ./logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
//“./” 表示同级目录 输出到同级目录的 logs/error.log中
### \u8F93\u51FAERROR \u7EA7\u522B\u4EE5\u4E0A\u7684\u65E5\u5FD7\u5230=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =./logs/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
步骤二:导入log4j
<!-- 日志标准的一种实现 -->
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- 通用日志标准的名字为slf4j -->
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.28</version>
</dependency>
<!-- 标准和实现的转化包 -->
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.28</version>
<scope>test</scope>
</dependency>
步骤三:在mybatis-config.xml 中配置
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"></setting>
</settings>
步骤四:在类中调用
//全局
private static final Logger log = LoggerFactory.getLogger(当前类名.class);
//方法中调用
log.info("测试日志打印");