快速入门
SpringBoot+Mybaits
idea新建项目
maven添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
添加配置文件
server:
port: 8001
servlet:
context-path: /
spring:
application:
name: cloud-payment-service
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
# driver-class-name: org.gjt.mm.mysql.Driver
url: dbc:mysql://localhost:3306/db_test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
username: root
password: 123456
type: com.alibaba.druid.pool.DruidDataSource
druid:
#初始化大小
initialSize: 5
#最小值
minIdle: 5
#最大值
maxActive: 20
#最大等待时间,配置获取连接等待超时,时间单位都是毫秒ms
maxWait: 60000
#配置间隔多久才进行一次检测,检测需要关闭的空闲连接
timeBetweenEvictionRunsMillis: 60000
#配置一个连接在池中最小生存的时间
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,
#'wall'用于防火墙,SpringBoot中没有log4j,我改成了log4j2
filters: stat,wall,log4j2
#最大PSCache连接
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
# 配置StatFilter
web-stat-filter:
#默认为false,设置为true启动
enabled: true
url-pattern: "/*"
exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*"
#配置StatViewServlet
stat-view-servlet:
url-pattern: "/druid/*"
#允许那些ip
allow: 127.0.0.1
login-username: admin
login-password: 123456
#禁止那些ip
deny: 192.168.1.102
#是否可以重置
reset-enable: true
#启用
enabled: true
mybatis:
mapperLocations: classpath:mapper:/*.xml
添加主启动类
@SpringBootApplication
public class PaymentMicro {
public static void main(String[] args) {
SpringApplication.run(PaymentMicro.class,args);
}
}
添加业务代码
添加测试代码
打包部署
mapper.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.jcoo.system.mapper.StorageFileMapper" >
<!--取别名-->
<typeAlias type="com.jcoo.system.model.StorageFile" alias="AS_StorageFile"/>
<!-- resultMap定义返回结果map id(常量名称) type(指定类型) -->
<resultMap id="BaseResultMap" type(指定类型)="AS_StorageFile" >
<!--id column主键列名 property:对应实体类成员名称 jdbcType:jdbc数据类型 >
<id column="storage_id" property="storageId" jdbcType="VARCHAR" />
<!--result column列名 >
<result column="storage_name" property="storageName" jdbcType="VARCHAR" />
<result column="original_name" property="originalName" jdbcType="VARCHAR" />
<result column="storage_prefix" property="storagePrefix" jdbcType="VARCHAR" />
<result column="storage_path" property="storagePath" jdbcType="VARCHAR" />
<result column="storage_fullpath" property="storageFullpath" jdbcType="VARCHAR" />
<result column="md5" property="md5" jdbcType="VARCHAR" />
<result column="extension" property="extension" jdbcType="VARCHAR" />
<result column="type" property="type" jdbcType="VARCHAR" />
<result column="size" property="size" jdbcType="BIGINT" />
<result column="attribute" property="attribute" jdbcType="VARCHAR" />
<result column="status" property="status" jdbcType="VARCHAR" />
<result column="brief" property="brief" jdbcType="VARCHAR" />
<result column="owner" property="owner" jdbcType="VARCHAR" />
<result column="creator" property="creator" jdbcType="VARCHAR" />
<result column="create_time" property="createTime" jdbcType="TIMESTAMP" />
<result column="modifier" property="modifier" jdbcType="VARCHAR" />
<result column="modify_time" property="modifyTime" jdbcType="TIMESTAMP" />
</resultMap>
<!-- sql可用来定义可重用的SQL代码段,可以包含在其他语句中-->
<sql id="Base_Column_List" >
storage_id, storage_name, original_name, storage_prefix, storage_path, storage_fullpath,
md5, extension, type, size, attribute, status, brief, owner, creator, create_time,
modifier, modify_time
</sql>
<!-- 查询 parameterType:输入参数变量类型-->
<!-- Mybatis传多个参数 : https://blog.csdn.net/bingospunky/article/details/52031908>-->
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.String" >
select
<include refid="Base_Column_List" />
from storage_file
where storage_id = #{storageId,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String" >
delete from storage_file
where storage_id = #{storageId,jdbcType=VARCHAR}
</delete>
<insert id="insert" parameterType="com.jcoo.system.model.StorageFile" >
insert into storage_file (storage_id, storage_name, original_name,
storage_prefix, storage_path, storage_fullpath,
md5, extension, type,
size, attribute, status,
brief, owner, creator,
create_time, modifier, modify_time
)
values (#{storageId,jdbcType=VARCHAR}, #{storageName,jdbcType=VARCHAR}, #{originalName,jdbcType=VARCHAR},
#{storagePrefix,jdbcType=VARCHAR}, #{storagePath,jdbcType=VARCHAR}, #{storageFullpath,jdbcType=VARCHAR},
#{md5,jdbcType=VARCHAR}, #{extension,jdbcType=VARCHAR}, #{type,jdbcType=VARCHAR},
#{size,jdbcType=BIGINT}, #{attribute,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR},
#{brief,jdbcType=VARCHAR}, #{owner,jdbcType=VARCHAR}, #{creator,jdbcType=VARCHAR},
#{createTime,jdbcType=TIMESTAMP}, #{modifier,jdbcType=VARCHAR}, #{modifyTime,jdbcType=TIMESTAMP}
)
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.jcoo.system.model.StorageFile" >
update storage_file
<set >
<if test="storageName != null" >
storage_name = #{storageName,jdbcType=VARCHAR},
</if>
<if test="originalName != null" >
original_name = #{originalName,jdbcType=VARCHAR},
</if>
<if test="storagePrefix != null" >
storage_prefix = #{storagePrefix,jdbcType=VARCHAR},
</if>
<if test="storagePath != null" >
storage_path = #{storagePath,jdbcType=VARCHAR},
</if>
<if test="storageFullpath != null" >
storage_fullpath = #{storageFullpath,jdbcType=VARCHAR},
</if>
<if test="md5 != null" >
md5 = #{md5,jdbcType=VARCHAR},
</if>
<if test="extension != null" >
extension = #{extension,jdbcType=VARCHAR},
</if>
<if test="type != null" >
type = #{type,jdbcType=VARCHAR},
</if>
<if test="size != null" >
size = #{size,jdbcType=BIGINT},
</if>
<if test="attribute != null" >
attribute = #{attribute,jdbcType=VARCHAR},
</if>
<if test="status != null" >
status = #{status,jdbcType=VARCHAR},
</if>
<if test="brief != null" >
brief = #{brief,jdbcType=VARCHAR},
</if>
<if test="owner != null" >
owner = #{owner,jdbcType=VARCHAR},
</if>
<if test="creator != null" >
creator = #{creator,jdbcType=VARCHAR},
</if>
<if test="createTime != null" >
create_time = #{createTime,jdbcType=TIMESTAMP},
</if>
<if test="modifier != null" >
modifier = #{modifier,jdbcType=VARCHAR},
</if>
<if test="modifyTime != null" >
modify_time = #{modifyTime,jdbcType=TIMESTAMP},
</if>
</set>
where storage_id = #{storageId,jdbcType=VARCHAR}
</update>
</mapper>
#{} 与 ${}
{} 会进行预处理
${} 直接拼接,会有sql注入风险
缓存
https://tech.meituan.com/2018/01/19/mybatis-cache.html
MyBatis支持二级缓存
- 总开关:全局配置(mybatis-config.xml)变量参数 cacheEnabled=true
- select语句所在的Mapper,配置了 或节点,并且有效
- select语句的参数 useCache=true
- Pojo类必须实现序列化接口
MyBatis对二级缓存的支持粒度很细,它会指定某一条查询语句是否使用二级缓存
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.String" useCache="true">
默认情况下并没有开启缓存,当需要开启二级缓存时,需要在SQL映射文件中添加:
映射语句文件中的所有 select 语句将会被缓存。
映射语句文件中的所有 insert,update 和 delete 语句会刷新缓存。
缓存会使用 Least Recently Used(LRU,最近最少使用的)算法来收回。
根据时间表(比如 no Flush Interval,没有刷新间隔), 缓存不会以任何时间顺序 来刷新。
缓存会存储列表集合或对象(无论查询方法返回什么)的 1024 个引用。
缓存会被视为是 read/write(可读/可写)的缓存,意味着对象检索不是共享的,而 且可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
代码生成器
mybatis-generator:maven插件
<build>
<plugins>
<!--mybatis自动生成代码插件-->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
<!-- 是否覆盖,true表示会替换生成的JAVA文件,false则不覆盖 -->
<overwrite>true</overwrite>
</configuration>
<dependencies>
<!--mysql驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
配置文件:
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>
<!-- 引入配置文件 -->
<properties resource="generatorConfig.properties"/>
<!-- <!– 指定数据连接驱动jar地址 –>-->
<!-- <classPathEntry location="${classPath}" />-->
<!-- 一个数据库一个context -->
<context id="DB2Tables" targetRuntime="MyBatis3">
<property name="id" value=""/>
<!-- 注释 -->
<commentGenerator>
<property name="suppressAllComments" value="true"/><!-- 是否取消注释 -->
<property name="suppressDate" value="false"/> <!-- 是否生成注释时间戳-->
</commentGenerator>
<!-- jdbc连接 -->
<jdbcConnection driverClass="${jdbc_driver}"
connectionURL="${jdbc_url}" userId="${jdbc_user}"
password="${jdbc_password}"/>
<!-- 类型转换 -->
<javaTypeResolver>
<!-- 是否使用bigDecimal, false可自动转化以下类型(Long, Integer, Short, etc.) -->
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- 生成实体类地址 -->
<javaModelGenerator targetPackage="${packageOfEntity}" targetProject="${packageOfProject}">
<!-- 是否在当前路径下新加一层schema,eg:fase路径com.oop.eksp.user.model, true:com.oop.eksp.user.model.[schemaName] -->
<property name="enableSubPackages" value="false"/>
<!-- 是否针对string类型的字段在set的时候进行trim调用 -->
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- 生成mapxml文件 -->
<sqlMapGenerator targetPackage="${packageOfMapperXML}" targetProject="${packageOfProject}">
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
<!-- 生成mapxml对应client,也就是接口dao -->
<javaClientGenerator targetPackage="${packageOfMapper}" targetProject="${packageOfProject}" type="XMLMAPPER">
<property name="enableSubPackages" value="false"/>
</javaClientGenerator>
<!-- 配置表信息 -->
<!--
1,schema:数据库的schema;
2,catalog:数据库的catalog;
3,alias:为数据表设置的别名,如果设置了alias,那么生成的所有的SELECT SQL语句中,列名会变成:alias_actualColumnName
4,domainObjectName:生成的domain类的名字,如果不设置,直接使用表名作为domain类的名字;可以设置为somepck.domainName,那么会自动把domainName类再放到somepck包里面;
5,enableInsert(默认true):指定是否生成insert语句;
6,enableSelectByPrimaryKey(默认true):指定是否生成按照主键查询对象的语句(就是getById或get);
7,enableSelectByExample(默认true):MyBatis3Simple为false,指定是否生成动态查询语句;
8,enableUpdateByPrimaryKey(默认true):指定是否生成按照主键修改对象的语句(即update);
9,enableDeleteByPrimaryKey(默认true):指定是否生成按照主键删除对象的语句(即delete);
10,enableDeleteByExample(默认true):MyBatis3Simple为false,指定是否生成动态删除语句;
11,enableCountByExample(默认true):MyBatis3Simple为false,指定是否生成动态查询总条数语句(用于分页的总条数查询);
12,enableUpdateByExample(默认true):MyBatis3Simple为false,指定是否生成动态修改语句(只修改对象中不为空的属性);
13,modelType:参考context元素的defaultModelType,相当于覆盖;
14,delimitIdentifiers:参考tableName的解释,注意,默认的delimitIdentifiers是双引号,如果类似MYSQL这样的数据库,使用的是`(反引号,那么还需要设置context的beginningDelimiter和endingDelimiter属性)
15,delimitAllColumns:设置是否所有生成的SQL中的列名都使用标识符引起来。默认为false,delimitIdentifiers参考context的属性
-->
<table tableName="storage_file" domainObjectName="StorageFile"
enableCountByExample="false"
enableDeleteByExample="false"
enableSelectByExample="false"
enableUpdateByExample="false">
<!-- schema即为数据库名 tableName为对应的数据库表 domainObjectName是要生成的实体类 enable*ByExample
是否生成 example类 -->
<!-- <!– 忽略列,不生成bean 字段 –>-->
<!-- <ignoreColumn column="FRED"/>-->
<!-- <!– 指定列的java数据类型 –>-->
<!-- <columnOverride column="LONG_VARCHAR_FIELD" jdbcType="VARCHAR"/>-->
</table>
<!-- 多个table -->
</context>
</generatorConfiguration>
generatorConfig.properties
jdbc_driver=com.mysql.jdbc.Driver
jdbc_url=jdbc:mysql://localhost:3306/db_jcoo?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false
jdbc_user=root
jdbc_password=123456
packageOfProject=src\\main\\java
packageOfEntity=com.jcoo.system.model
packageOfMapper=com.jcoo.system.mapper
packageOfMapperXML=com.jcoo.system.mapper
探究
Mybatis 与 Maven
Mybatis报错: Invalid bound statement (not found) 错误
在使用maven进行依赖管理时,需要注意mybatis需要的Mapper.xml文件(X)与Mapper.java文件(J)的位置关系
如果X文件在Resource目录下,需要在Resource目录新建与J所在包相同层级的目录,并配置mapper-locations
mapper-locations: - classpth:com.jcoo.jclab.mapper/*Mapper.xml
如果X文件在与J所在包相同层级的目录(代码目录)下,需要在pom文件的bulid下加入<build> <resources> <resource> <directory>src/main/java</directory><!--所在的目录--> <includes> <include>**/*.MapperXml</include> </includes> </resource> </resources> </build>
(maven默认只认Resource目录下资源文件)
这样启动应用时maven构建生成的target下Mapper类和Mapper.xml才在同一路径下
注意:如果使用第二种方式在使用代码插件时,如果插件的配置文件xml中使用引入properties文件会出现如下错误:,可能在每次生成代码时需要注释resource
MapperScan
Mybatis报错:xxxMapper that could not be found [Autowired(required=true)] 错误
@MapperScan(“com.jcoo.system.mapper”):扫描包下面的接口类,在编译之后都会生成相应的实现类
为什么说 MyBatis 是半ORM?
说 MyBatis 是 半自动 ORM 最主要的一个原因是,它需要在 XML 或者注解里通过手动或插件生成 SQL,才能完成 SQL 执行结果与对象映射绑定。
参考
- mybaits参考文档 https://mybatis.org/mybatis-3/zh/index.html
- mybatis plus教程 https://baomidou.com/guide/