MyBatis是一个基于Java语言的持久层框架,它通过XML描述符或注解将对象与存储过程或SQL语句进行映射,并提供了普通SQL查询、存储过程和高级映射等操作方式,使得操作数据库变得非常方便。
MyBatis是Apache下的一个开源项目,其前身是iBATIS,它在2002年由Clinton Begin首次发布。2010年5月,该项目由iBATIS更名为MyBatis,同时推出了第一版MyBatis 3,在整个持久层框架市场上引起了很大的关注和广泛的应用。
在iBATIS项目中,XML描述符是核心并且是唯一的形式,它为开发人员提供了很大的灵活性,然而也产生了一些问题,如繁琐、容易出错等。
在MyBatis 3中,Mapper接口和注解成为了主流的配置方式,XML描述符仍然被支持,但不再是唯一的形式。同时,MyBatis 3大量采用了Java 5.0注解,使得代码更加简洁明了。
MyBatis的安装十分简单,只需要在项目的pom.xml文件中添加如下依赖即可:
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
</dependencies>
另外,如果需要使用MyBatis Generator来自动生成Java代码和MyBatis映射文件,则还需要添加如下插件:
<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.4.0</version>
<configuration>
<!-- MyBatis Generator配置文件的位置 -->
<configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
<overwrite>true</overwrite>
<verbose>true</verbose>
</configuration>
</plugin>
</plugins>
MyBatis并没有内置数据库连接池,因此需要使用第三方的数据库连接池。常见的数据库连接池有如下几种:
在实际使用中,我们可以根据自己的需求选择合适的数据库连接池,这里以HikariCP为例进行演示。可以通过以下方式添加HikariCP的依赖:
<dependencies>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>4.0.3</version>
</dependency>
</dependencies>
MyBatis的配置文件是一个XML文件,包含了MyBatis的大部分配置信息,例如数据库连接信息、映射文件位置、缓存配置等。下面是一个简单的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>
<!-- 数据库连接信息 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="com.zaxxer.hikari.HikariDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=Asia/Shanghai"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 扫描映射文件 -->
<mappers>
<mapper resource="com/example/demo/mapper/UserMapper.xml"/>
</mappers>
</configuration>
其中,<environments>
标签用于指定数据库连接信息,包括事务管理器和数据源信息。这里使用了HikariCP来作为数据源,同时指定了MySQL数据库的连接信息。
<mappers>
标签用于指定映射文件的位置,这里指定了一个映射文件,并指定了它的资源路径。
MyBatis也支持使用YAML格式来进行配置,相对于XML格式更加简洁直观。以下是一个基于YAML格式配置的样例:
# MyBatis 配置
mybatis:
# 别名配置
typeAliasesPackage: com.example.demo.entity
# Mapper XML文件存放路径
mapperLocations: classpath*:mapper/*.xml
# 数据库连接池配置
datasource:
url: jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
hikari:
minimumIdle: 5
maximumPoolSize: 20
idleTimeout: 300000
connectionTimeout: 30000
其中,typeAliasesPackage
用于设置实体类的包路径,mapperLocations
用于指定Mapper XML文件的位置,datasource
用于配置数据库连接池,可以设置连接池的参数。
在MyBatis中,还可以使用注解来进行配置,不再需要XML或YAML格式的配置文件。以下是一个基于注解的样例:
// 实体类
public class User {
private Long id;
private String username;
private Integer age;
// getter、setter方法省略
}
// Dao接口
@Mapper
public interface UserDao {
@Select("SELECT * FROM user WHERE id = #{id}")
User findById(Long id);
@Insert("INSERT INTO user(username, age) VALUES (#{username}, #{age})")
int save(User user);
@Update("UPDATE user SET username = #{username}, age = #{age} WHERE id = #{id}")
int update(User user);
@Delete("DELETE FROM user WHERE id = #{id}")
int deleteById(Long id);
}
// 配置类
@Configuration
@MapperScan("com.example.demo.mapper")
public class MybatisConfig {
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
sessionFactory.setMapperLocations(resolver.getResources("classpath*:mapper/*.xml"));
return sessionFactory.getObject();
}
}
以上代码使用了@Mapper
注解来标识Dao接口,并使用@Select
、@Insert
、@Update
、@Delete
等注解来进行SQL操作的配置。在MybatisConfig
中,使用了@MapperScan
注解来指定Mapper类的扫描路径,并使用SqlSessionFactoryBean
来进行SqlSessionFactory的配置。
MyBatis的核心是SQL映射语句,而SQL映射语句则是以XML文件的形式维护在项目中。以下是一个简单的MyBatis映射文件的示例:
<?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.example.demo.mapper.UserMapper">
<!-- 查询操作 -->
<select id="findById" parameterType="Long" resultType="User">
SELECT *
FROM user
WHERE id = #{id}
</select>
<!-- 插入操作 -->
<insert id="save" parameterType="User">
INSERT INTO user(username, age)
VALUES (#{username}, #{age})
</insert>
<!-- 更新操作 -->
<update id="update" parameterType="User">
UPDATE user SET
username = #{username},
age = #{age}
WHERE id = #{id}
</update>
<!-- 删除操作 -->
<delete id="deleteById" parameterType="Long">
DELETE FROM user
WHERE id = #{id}
</delete>
</mapper>
其中,<mapper>
标签用于定义命名空间,这里指定了com.example.demo.mapper.UserMapper
作为命名空间。
<select>
标签用于定义查询操作,id
属性表示该SQL语句的唯一标识,parameterType
表示参数类型,resultType
表示返回值类型。在这个例子中,findById
是查询用户信息的语句。
<insert>
、<update>
、<delete>
标签分别表示插入、更新和删除操作,它们的语法与<select>
标签类似。
有了映射文件之后,我们就可以使用Java代码来进行数据库操作了。
public interface UserMapper {
// 查询操作
User findById(Long id);
// 插入操作
int save(User user);
// 更新操作
int update(User user);
// 删除操作
int deleteById(Long id);
}
首先定义一个接口,其中包含几个基本的CRUD操作。
@Mapper
public interface UserMapper {
User findById(Long id);
int save(User user);
int update(User user);
int deleteById(Long id);
}
然后使用@Mapper
注解标识该接口为Mapper接口。MyBatis会自动扫描这些接口并创建对应的实现类。
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User findById(Long id) {
return userMapper.findById(id);
}
@Override
public int save(User user) {
return userMapper.save(user);
}
@Override
public int update(User user) {
return userMapper.update(user);
}
@Override
public int deleteById(Long id) {
return userMapper.deleteById(id);
}
}
最后,在Service层中注入Mapper接口,并使用对应的方法进行数据库操作。
@SpringBootApplication
@MapperScan("com.example.demo.mapper")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
在Spring Boot主类中加上@MapperScan
注解,指定Mapper接口的扫描路径。
通过以上步骤,我们就可以完成基本的CRUD操作。
在实际开发中,我们需要根据不同的条件动态生成SQL语句,这时就需要使用MyBatis提供的动态SQL功能。常用的动态SQL元素有if
、where
、foreach
等。
if
元素可以用于根据条件判断是否包含某个SQL语句片段。
例如,我们需要查询年龄大于18岁且小于等于30岁的用户信息,可以这样编写SQL语句:
<select id="findUsersByAge" parameterType="Map" resultType="User">
SELECT *
FROM user
WHERE 1 = 1
<if test="minAge != null">
AND age >= #{minAge}
</if>
<if test="maxAge != null">
AND age <= #{maxAge}
</if>
</select>
以上代码中,<if>
元素用于判断minAge
和maxAge
是否为null,如果不为null,则将对应的SQL语句片段拼接到最终的SQL语句中。
where
元素可以用于动态生成WHERE
子句,如果所有条件均为null,则不会生成WHERE
子句。
例如,我们需要查询用户名和密码匹配的用户信息,可以这样编写SQL语句:
<select id="findUserByUsernameAndPassword" parameterType="Map" resultType="User">
SELECT *
FROM user
<where>
<if test="username != null">
AND username = #{username}
</if>
<if test="password != null">
AND password = #{password}
</if>
</where>
</select>
以上代码中,<where>
元素用于动态生成WHERE
子句,如果username
和password
均为null,则不会生成WHERE
子句。
foreach
元素可以用于循环遍历一个集合,并将集合中的元素拼接到SQL语句中。
例如,我们需要查询多个用户信息,可以这样编写SQL语句:
<select id="findUsersByIds" parameterType="List" resultType="User">
SELECT *
FROM user
WHERE id IN
<foreach collection="list" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
以上代码中,<foreach>
元素用于循环遍历List
类型的参数,并将集合中的元素拼接到SQL语句中。
在MyBatis中,插入操作分为手动指定ID和数据库自动生成ID两种方式。
如果需要手动指定ID,可以这样编写SQL语句:
<insert id="save" parameterType="User">
INSERT INTO user(id, username, password, age)
VALUES (#{id}, #{username}, #{password}, #{age})
</insert>
以上代码中,将插入的ID值直接作为参数传入插入语句中。
如果需要数据库自动生成ID,可以这样编写SQL语句:
<insert id="save" parameterType="User" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user(username, password, age)
VALUES (#{username}, #{password}, #{age})
</insert>
以上代码中,通过useGeneratedKeys="true"
参数告诉MyBatis要求数据库生成主键,并通过keyProperty="id"
参数指定了主键的属性名。这样,当执行插入操作后,主键值将自动赋值到User
对象的id
属性中。
删除操作比较简单,可以这样编写SQL语句:
<delete id="deleteById" parameterType="Long">
DELETE FROM user
WHERE id = #{id}
</delete>
以上代码中,直接通过传入的id
参数进行删除操作。
更新操作也比较简单,可以这样编写SQL语句:
<update id="update" parameterType="User">
UPDATE user SET
username = #{username},
password = #{password},
age = #{age}
WHERE id = #{id}
</update>
以上代码中,通过传入的User
对象进行更新操作。
在实际应用中,常常需要进行多表关联查询,MyBatis提供了<association>
和<collection>
标签来完成多表关联查询。
例如,我们有两个表,分别是user
表和card
表,每个用户都有一张银行卡,通过userId
列可以进行关联查询。可以这样编写SQL语句:
<select id="findUsersWithCards" resultType="User">
SELECT u.*, c.*
FROM user u
INNER JOIN card c ON u.id = c.userId
</select>
以上代码中,通过INNER JOIN
连接两个表,并使用u.*
和c.*
来选择需要查询的列。
然而,直接返回结果集会将所有数据都映射到User
对象中,并不符合我们的需求。此时,可以使用<resultMap>
标签来自定义结果映射规则。
<resultMap id="userMap" type="User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
<result property="age" column="age"/>
<association property="card" javaType="Card">
<id property="id" column="cardId"/>
<result property="cardCode" column="cardCode"/>
<result property="balance" column="balance"/>
<result property="userId" column="userId"/>
</association>
</resultMap>
<select id="findUsersWithCards" resultMap="userMap">
SELECT u.id, u.username, u.password, u.age, c.id AS cardId, c.cardCode, c.balance, c.userId
FROM user u
INNER JOIN card c ON u.id = c.userId
</select>
以上代码中,<resultMap>
标签定义了结果映射规则,包括主键、普通属性和关联属性。其中,<association>
标签指定了一个一对一关联关系,并通过property
属性指向User
对象中的Card
属性。
例如,我们有两个表,分别是user
表和address
表,每个用户可以有多个地址,通过userId
列可以进行关联查询。可以这样编写SQL语句:
<select id="findUsersWithAddresses" resultMap="userMap">
SELECT u.*, a.*
FROM user u
INNER JOIN address a ON u.id = a.userId
</select>
以上代码中,同样使用INNER JOIN
连接两个表。
然而,直接返回结果集会将所有数据都映射到User
对象中,并不符合我们的需求。此时,可以使用<collection>
标签来指定一个一对多关联关系,并通过property
属性指向User
对象中的addresses
属性。
<resultMap id="userMap" type="User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
<result property="age" column="age"/>
<collection property="addresses" ofType="Address">
<id property="id" column="id"/>
<result property="address" column="address"/>
<result property="userId" column="userId"/>
</collection>
</resultMap>
<select id="findUsersWithAddresses" resultMap="userMap">
SELECT u.id, u.username, u.password, u.age, a.id, a.address, a.userId
FROM user u
INNER JOIN address a ON u.id = a.userId
</select>
以上代码中,<collection>
标签指定了一个一对多关联关系,并通过ofType
属性指定目标类型为Address
。
MyBatis提供了缓存机制,这可以有效地减少与数据库的交互次数,提高系统性能。
默认情况下,MyBatis会开启一级缓存(SqlSession级别的缓存)和二级缓存(全局共享的缓存)。
<!-- 配置全局二级缓存 -->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
以上代码中,通过配置<cache>
标签来启用全局二级缓存,并指定了使用Ehcache作为缓存实现方式。
在自定义Mapper接口中,可以通过@CacheNamespace
注解来启用单独的二级缓存。
@CacheNamespace
public interface UserMapper {
// ...
}
以上代码中,通过@CacheNamespace
注解来启用UserMapper的二级缓存。
需要注意的是,如果在进行insert、update、delete等操作时,MyBatis会清空该namespace下的所有缓存。
MyBatis提供了分页插件,这可以方便地实现分页查询功能。
首先,引入分页插件jar包,例如使用PageHelper插件:
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.11</version>
</dependency>
然后,在MyBatis配置文件中配置分页插件:
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"/>
</plugins>
最后,在自定义Mapper接口方法中使用分页插件来完成分页查询:
public interface UserMapper {
List<User> findUsersByPage(@Param("pageNum") int pageNum, @Param("pageSize") int pageSize);
}
以上代码中,使用@Param
注解来指定传入的参数名,使用PageHelper插件来实现分页查询。
@Test
public void testFindUsersByPage() {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
PageHelper.startPage(2, 3);
List<User> users = userMapper.findUsersByPage();
for (User user : users) {
System.out.println(user);
}
PageInfo<User> pageInfo = new PageInfo<>(users);
System.out.println("当前页:" + pageInfo.getPageNum());
System.out.println("每页记录数:" + pageInfo.getPageSize());
System.out.println("总记录数:" + pageInfo.getTotal());
System.out.println("总页数:" + pageInfo.getPages());
System.out.println("是否第一页:" + pageInfo.isIsFirstPage());
System.out.println("是否最后一页:" + pageInfo.isIsLastPage());
} finally {
sqlSession.close();
}
}
以上代码中,使用PageHelper.startPage()
方法来指定分页查询的页码和每页记录数,使用PageInfo
类来获取分页相关信息。
MyBatis和Spring的整合,可以通过Spring提供的SqlSessionFactoryBean
和MapperScannerConfigurer
来实现。
其中,SqlSessionFactoryBean
负责创建SqlSessionFactory对象,MapperScannerConfigurer
负责将Mapper接口扫描注册到Spring容器中,以便在应用中注入并使用。
首先,引入MyBatis和Spring相关jar包,例如:
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.6</version>
</dependency>
然后,在Spring配置文件中配置SqlSessionFactoryBean
和MapperScannerConfigurer
:
<!-- 配置SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!-- 注册Mapper接口 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.example.mapper"/>
</bean>
以上代码中,通过SqlSessionFactoryBean
配置SqlSessionFactory对象,并指定数据源和MyBatis配置文件路径。通过MapperScannerConfigurer
注册Mapper接口,其中basePackage
指定了Mapper接口所在的包路径。
最后,在需要使用Mapper接口的地方,注入该接口,并使用。
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User getUserById(int id) {
return userMapper.getUserById(id);
}
}
以上代码中,通过@Autowired
注解将UserMapper
接口注入到UserServiceImpl
中,并在方法实现中使用该接口。
MyBatis Generator是MyBatis官方提供的一个开源项目,可以根据数据库表自动生成对应的Java实体类、Mapper接口和XML文件,极大地简化了开发工作。
具体来说,MyBatis Generator会根据指定的数据库连接信息、表名规则、生成策略等参数,自动生成Java实体类和Mapper接口。同时,还可以根据表结构自动生成SQL语句,并将其配置到XML文件中,以便直接使用。
通常情况下,MyBatis Generator会为每个表生成3个文件:
src/main/java
下的指定包路径中。src/main/java
下的指定包路径中。src/main/resources
下的指定包路径中。在生成XML文件时,MyBatis Generator提供了不同的生成策略,如:
*Mapper.xml
命名。*Mapper.xml
命名,并在Java类中通过@Mapper
注解来指定XML文件名。首先,引入MyBatis Generator相关jar包和数据库驱动,例如:
<!-- MyBatis Generator -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.4.0</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.24</version>
</dependency>
然后,在项目根目录下新建一个generatorConfig.xml
配置文件,其中包含数据库连接信息、表名规则、生成策略、Java类型映射等。
<?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>
<!-- 数据库连接信息 -->
<context id="mysql" targetRuntime="MyBatis3">
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC"
userId="root"
password="root"/>
<!-- 表名规则 -->
<table tableName="user" domainObjectName="User"/>
<!-- Java类型映射 -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- Mapper接口生成策略 -->
<javaClientGenerator targetPackage="com.example.mapper"
targetProject="src/main/java"
type="XMLMAPPER"/>
<!-- XML文件生成策略 -->
<sqlMapGenerator targetPackage="mapper"
targetProject="src/main/resources"
type="XML"/>
<!-- Java实体类生成策略 -->
<javaModelGenerator targetPackage="com.example.entity"
targetProject="src/main/java"
enableSubPackages="true"
xmlAccessor="PUBLIC"/>
<!-- 表字段和Java属性名映射 -->
<tableFieldOverride column="id" property="id" />
<tableFieldOverride column="username" property="username" />
<tableFieldOverride column="password" property="password" />
<tableFieldOverride column="age" property="age" />
</context>
</generatorConfiguration>
以上代码中,通过jdbcConnection
指定数据库连接信息。使用<table>
标签指定要生成Java实体类和Mapper接口的表,其中tableName
指定表名,domainObjectName
指定Java实体类名。
通过<javaTypeResolver>
指定Java类型映射,例如将bigint映射到Long类型。通过<javaClientGenerator>
、<sqlMapGenerator>
和<javaModelGenerator>
分别设置Java实体类生成路径、Mapper接口生成路径和XML文件生成路径及文件名。
最后,在根目录下打开命令行窗口,执行以下命令即可自动生成代码:
$ java -jar mybatis-generator-core-x.x.x.jar -configfile generatorConfig.xml -overwrite
其中,mybatis-generator-core-x.x.x.jar
为MyBatis Generator的jar包。-configfile
参数指定配置文件名,-overwrite
参数表示覆盖已有文件。执行完成后,即可在指定路径下看到生成的代码文件。
示例:使用MyBatis Generator生成Java实体类、Mapper接口和XML文件,假设有一张名为account
的表,该表包含id、name和balance三个字段。
首先,在generatorConfig.xml
配置文件中添加以下代码:
<context id="mysql" targetRuntime="MyBatis3">
<!-- ... -->
<!-- 表名规则 -->
<table tableName="account" domainObjectName="Account"/>
<!-- ... -->
</context>
然后,在根目录下打开命令行窗口,执行以下命令:
$ java -jar mybatis-generator-core-x.x.x.jar -configfile generatorConfig.xml -overwrite
执行完成后,可以在指定路径下看到生成的代码文件:
com.example.entity.Account.java
com.example.mapper.AccountMapper.java
mapper/AccountMapper.xml
MyBatis Plus是一款MyBatis框架的增强工具,提供了很多实用的功能,可以极大地简化开发工作。其主要功能包括:
MyBatis Plus的主要优点有:
MyBatis Plus的局限性主要有:
首先,在项目中引入MyBatis Plus相关的jar包:
<!-- MyBatis Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.5</version>
</dependency>
MyBatis Plus提供了官方的代码生成器,可以根据数据库表自动生成Java实体类、Mapper接口及其XML文件。使用方法如下:
application.properties
配置文件中,添加以下代码:```properties # 数据库连接信息 spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC&characterEncoding=utf-8 spring.datasource.username=root spring.datasource.password=root
# MyBatis Plus配置 mybatis-plus.mapper-locations=classpath:mapper/*.xml mybatis-plus.type-aliases-package=com.example.entity mybatis-plus.configuration.cache-enabled=false mybatis-plus.global-config.id-type=auto ```
其中,spring.datasource.url
为数据库连接信息,mybatis-plus.mapper-locations
表示Mapper接口对应的XML文件所在路径,mybatis-plus.type-aliases-package
表示Java实体类所在包路径。
```java public class CodeGenerator { public static void main(String[] args) { // 数据源配置 DataSourceConfig dataSourceConfig = new DataSourceConfig(); dataSourceConfig.setDbType(DbType.MYSQL) .setUrl(“jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC&characterEncoding=utf-8”) .setUsername(“root”) .setPassword(“root”) .setDriverName(“com.mysql.cj.jdbc.Driver”);
// 全局配置
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setOutputDir(System.getProperty("user.dir") + "/src/main/java")
.setAuthor("binjie09")
.setOpen(false)
.setFileOverride(true)
.setIdType(IdType.AUTO)
.setBaseResultMap(true)
.setBaseColumnList(true);
// 包配置
PackageConfig packageConfig = new PackageConfig();
packageConfig.setParent("com.example")
.setEntity("entity")
.setMapper("mapper")
.setXml("mapper.xml")
.setService("service")
.setServiceImpl("service.impl")
.setController("controller");
// 策略配置
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setCapitalMode(true)
.setNaming(NamingStrategy.underline_to_camel)
.setTablePrefix("t_")
.setInclude("user");
// 代码生成器
AutoGenerator autoGenerator = new AutoGenerator();
autoGenerator.setDataSource(dataSourceConfig)
.setGlobalConfig(globalConfig)
.setPackageInfo(packageConfig)
.setStrategy(strategyConfig)
.execute();
}
} ```
其中,dataSourceConfig
为数据源配置,globalConfig
为全局配置,packageConfig
为包配置,strategyConfig
为策略配置。创建了相应的配置后,调用AutoGenerator
的execute()
方法即可生成代码。
在以上代码中,setInclude("user")
表示只生成user
表对应的Java实体类、Mapper接口及其XML文件,也可不传入参数表示生成所有表的代码。
```java public class CodeGenerator { public static void main(String[] args) { // …
// 执行生成器
autoGenerator.execute();
}
} ```
使用MyBatis Plus进行Lambda表达式查询,需要先引入LambdaQueryWrapper类,例如:
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
然后,可以进行如下Lambda表达式查询:
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public List<User> listUsersByName(String name) {
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(User::getName, name);
return userMapper.selectList(queryWrapper);
}
}
以上代码中,queryWrapper.like(User::getName, name)
表示查询name
字段包含name
字符串的记录,而User::getName
表示获取User
对象的name
属性。
使用MyBatis Plus进行分页查询可以很简单地实现,例如:
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public IPage<User> listUsersByPage(int pageNum, int pageSize) {
Page<User> page = new Page<>(pageNum, pageSize);
return userMapper.selectPage(page, null);
}
}
以上代码中,通过new Page<>(pageNum, pageSize)
创建了分页对象,即第pageNum
页,每页展示pageSize
条数据。然后,调用IPage<User> selectPage(IPage<User> page, Wrapper<User> queryWrapper)
方法进行分页查询。
MyBatis Plus提供了多租户插件,可以轻松实现多租户场景。首先,在application.yml
配置文件中添加以下代码:
mybatis-plus:
configuration:
# 指定多租户插件类
plugins: com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor
global-config:
# 指定租户ID列名
tenant-id-column: tenant_id
# 指定租户ID处理器
tenant-handler: com.example.handler.MultiTenantHandler
其中,com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor
为多租户插件类,tenant-id-column
指定租户ID列名,tenant-handler
指定租户ID处理器。
然后,在MultiTenantHandler
中编写租户ID过滤逻辑,例如:
public class MultiTenantHandler implements TenantHandler {
private static final String DEFAULT_TENANT_ID = "1";
@Override
public Expression getTenantId(boolean where) {
// 获取当前租户ID,可以从Session、ThreadLocal等获取
String tenantId = TenantContext.getTenantId();
// 如果没有获取到租户ID,则使用默认的租户ID
if (tenantId == null || "".equals(tenantId.trim())) {
tenantId = DEFAULT_TENANT_ID;
}
return new LongValue(tenantId);
}
@Override
public String getTenantIdColumn() {
return "tenant_id";
}
@Override
public boolean doTableFilter(String tableName) {
// 过滤掉不需要进行租户ID过滤的表
return !"user".equalsIgnoreCase(tableName);
}
}
以上代码中,getTenantId()
方法用于获取当前租户ID,getTenantIdColumn()
方法返回租户ID列名,doTableFilter()
方法用于过滤掉不需要进行租户ID过滤的表。
最后,在Mapper接口的查询语句中添加@SqlParser(filter=true)
注解即可启用多租户插件,例如:
public class MultiTenantHandler implements TenantHandler {
private static final String DEFAULT_TENANT_ID = "1";
@Override
public Expression getTenantId(boolean where) {
// 获取当前租户ID,可以从Session、ThreadLocal等获取
String tenantId = TenantContext.getTenantId();
// 如果没有获取到租户ID,则使用默认的租户ID
if (tenantId == null || "".equals(tenantId.trim())) {
tenantId = DEFAULT_TENANT_ID;
}
return new LongValue(tenantId);
}
@Override
public String getTenantIdColumn() {
return "tenant_id";
}
@Override
public boolean doTableFilter(String tableName) {
// 过滤掉不需要进行租户ID过滤的表
return !"user".equalsIgnoreCase(tableName);
}
}
以上代码中,getTenantId()
方法用于获取当前租户ID,getTenantIdColumn()
方法返回租户ID列名,doTableFilter()
方法用于过滤掉不需要进行租户ID过滤的表。
最后,在Mapper接口的查询语句中添加@SqlParser(filter=true)
注解即可启用多租户插件,例如:
@Mapper
public interface UserMapper extends BaseMapper<User> {
@SqlParser(filter=true)
@Override
List<User> selectList(@Param(Constants.WRAPPER) Wrapper<User> queryWrapper);
// ...
}
以上代码中,@SqlParser(filter=true)
注解表示启用过滤器,对selectList()
方法进行租户ID过滤。
在使用MyBatis进行开发之前,首先要掌握好数据表的设计。好的数据表设计可以极大地提高查询效率,降低系统复杂度。下面介绍一些数据表设计的要点。
user_info
。user_id
。id
。VARCHAR(255)
,而不是TEXT
或者MEDIUMTEXT
。在设计数据表时,需要考虑好表与表之间的关系,包括一对一、一对多和多对多等关系。下面介绍一些常见的表关系设计。
MyBatis的映射文件用于定义SQL语句和映射规则,下面介绍一些映射文件编写的要点。
<resultMap>
、<association>
、<collection>
等。需要根据不同情况选择合适的映射关系标签。getUserById
、listUsers
等。not-null="true"
表示该属性不能为空。<resultMap id="userMap" type="User">
<id column="id" property="id"/>
<result column="username" property="username"/>
<discriminator javaType="int" column="type">
<case value="1" resultMap="studentMap"/>
<case value="2" resultMap="teacherMap"/>
</discriminator>
</resultMap>
<resultMap id="studentMap" type="Student">
<result column="score" property="score"/>
</resultMap>
<resultMap id="teacherMap" type="Teacher">
<result column="title" property="title"/>
</resultMap>
以上代码中,使用<discriminator>
标签进行分发处理,当查询结果中的type
列值为1
时,使用studentMap
映射;当type
列值为2
时,使用teacherMap
映射。
子查询指的是将一个SQL语句嵌套到另一个SQL语句中,作为另一个SQL语句的一部分进行查询操作。虽然使用子查询可以实现较为复杂的查询操作,但是也会带来一些性能问题,主要表现在以下几个方面:
因此,在编写SQL语句时,应该尽可能避免使用子查询。可以通过以下几种方式来替代使用子查询的情况:
以下是一个使用多表连接查询替代子查询的示例:
-- 子查询
SELECT * FROM orders WHERE customer_id IN (SELECT id FROM customers WHERE name LIKE '%张三%');
-- 多表连接查询
SELECT o.* FROM orders o JOIN customers c ON o.customer_id = c.id WHERE c.name LIKE '%张三%';
%前缀模糊查询指的是在查询字符串时,使用%作为前缀进行模糊匹配。虽然使用%前缀模糊查询可以实现快速查找匹配字符串的功能,但同时也会带来一些性能问题,主要表现在以下几方面:
因此,在编写SQL语句时,应该尽可能避免使用%前缀模糊查询。可以通过以下方式来替代使用%前缀模糊查询的情况:
以下是一个使用全文索引替代%前缀模糊查询的示例:
-- %前缀模糊查询
SELECT * FROM articles WHERE title LIKE '%关键词%';
-- 全文索引查询
SELECT * FROM articles WHERE MATCH(title) AGAINST('关键词' IN NATURAL LANGUAGE MODE);
MyBatis作为一款优秀的ORM框架,其使用广泛,功能也非常强大。MyBatis的未来发展方向主要包括以下几个方面:
在使用MyBatis时,需要注意以下事项:
在使用MyBatis过程中,也存在一些常见问题,例如:
以下是一个使用全文索引替代%前缀模糊查询的示例:
-- %前缀模糊查询
SELECT * FROM articles WHERE title LIKE '%关键词%';
-- 全文索引查询
SELECT * FROM articles WHERE MATCH(title) AGAINST('关键词' IN NATURAL LANGUAGE MODE);
MyBatis作为一款优秀的ORM框架,其使用广泛,功能也非常强大。MyBatis的未来发展方向主要包括以下几个方面:
在使用MyBatis时,需要注意以下事项:
在使用MyBatis过程中,也存在一些常见问题,例如: