MyBatis学习笔记
一、简介
1.1 什么是MyBatis?
-
MyBatis 是一款优秀的持久层框架
-
持久层:就是数据访问层DAL,主要功能就是负责数据库的访问。
Dao层、Service层、Controller层
-
-
它支持自定义 SQL、存储过程以及高级映射。免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
-
MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
1.2 MyBatis的作用
- 简化JDBC代码,提供持久化的能力,帮助开发人员将数据存入到数据库中
二、MyBatis程序
2.1 项目的创建
-
新建一个Maven项目
-
删除src文件,这样使当前工程成为父工程
-
导入依赖到项目的pom.xml文件中
<dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>
2.2 模块的创建
在项目中创建一个Maven模块
从XML中构建SqlSessionFactory
由于每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的,SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。
1. 配置MyBatis工具类
通过 SqlSessionFactoryBuilder 获得SqlSessionFactory 的实例。在java文件下创建一个utils包,然后创建一个MybatisUtils类文件。
package com.rainlx.utils;
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 java.io.IOException;
import java.io.InputStream;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory; //
static {
try {
//构建获取sqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//SqlSession 提供了在数据库执行 SQL 命令所需的所有方法
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
2. MyBatis核心配置文件
- 在resources文件中创建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="org/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
-
DataSource中的"url"、“username”、"password"都是数据库的信息,具体的值和连接的数据库有关。
-
配置好的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="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test01?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--所有的Mapper.xml配置文件都要在MyBatis核心配置文件中注册-->
<mappers>
<mapper resource="com/rainlx/dao/UserMapper.xml"/>
</mappers>
</configuration>
PS:所有的Mapper.xml文件一定要在mybatis-config.xml中注册
2.3 项目代码
代码中要有实体类、接口、实现类
2.3.1 实体类
java文件下创建pojo包,再创建数据库的User实体类
实体类中声明数据库中的关键字,同时有构造器、get、set方法
public class User {
private int id;
private String username;
private String pwd;
public User() {
}
public User(int id, String username, String pwd) {
this.id = id;
this.username = username;
this.pwd = pwd;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
2.3.2 Mapper(Dao)接口
public interface UserMapper {
List<User> getUserList();
}
2.3.3 接口实现类
-
接口实现类可以由一个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"> <!--namespace实现接口绑定,包名要和接口名保持一致--> <mapper namespace="com.rainlx.dao.UserMapper"> <!--id中写的是接口类中的方法名,resultType中写的是下面sql语句返回的结果类型--> <!--select返回一个查询结果的集合,集合的泛型是User类型--> <select id="getUserList" resultType="com.rainlx.pojo.User"> select * from test01.user </select> </mapper>
- 实现类中的命名空间,要用全限定名来实现接口绑定
- 绑定接口之后,要在核心配置文件mybatis-config.xml中注册mapper
- 接口实现类也可以通过Java注解来配置完成语句映射。
2.3.4 测试
public class UserDaoTest {
@Test
public void test(){
SqlSession session = MyBatisUtils.getSqlSession(); //首先获取SqlSession对象;
UserMapper mapper = session.getMapper(UserMapper.class); //执行SQL要先拿到SQL,所以去getMapper到UserDao接口
List<User> userList = mapper.getUserList(); //上一步返回mapper对象之后,就可以执行接口中声明的方法了
for (User user : userList) {
System.out.println(user);
}
session.close(); //关闭SqlSession
}
}
运行结果:
User{id=1, username='admin', pwd='admin'}
User{id=2, username='manager', pwd='123456'}
User{id=3, username='test', pwd='123'}
2.4 程序中出现的问题
- “[08S01] Communications link failure The last packet sent successfully to the server was 0 milliseconds ago"
**解决方法:**尝试在Windows的服务设置中启动MySQL服务
-
IDEA连接MtSQL时可能出现“Server returns invalid timezone”的错误
**解决方法:**设置MySQL驱动的时区
-
执行测试后,如果出现“java.lang.ExceptionInInitializerError”
**解决方法:**在项目和Module的pom.xml文件中,添加:
<build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
-
如果出现“lineNumber: 8; columnNumber: 19; 2 字节的 UTF-8 序列的字节 2 无效”
**解决方法:**修改文件编码,setting -> Editor -> file Encodings
-
如果出现“Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure”
在网上看了各种解决方法都不行,最后找到一个不清楚原理的方法
**解决方法:**在mybatis-config.xml配置文件中,将数据库url中的“useSSL=true&useUnicode=true&”修改为“useSSL=false&useUnicode=false”
原内容为:
<property name="url" value="jdbc:mysql://localhost:3306/test01?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
修改后的内容为:
<property name="url" value="jdbc:mysql://localhost:3306/test01?useSSL=false&useUnicode=false&characterEncoding=UTF-8"/>
一个MyBatis程序,需要有的7项内容,为了防止配置文件加载失败的错误发生,直接在项目和Module的pom.xml文件的中添加配置文件信息,详细内容见第2.4节第4部分。
-
执行测试时如果出现“class not found”的错误,先去检查target文件夹下是否有生成test-classes,该文件夹下是否有测试类文件的生成
如果没有,可能是因为执行mvn clean后,编译好的class文件被删除掉了,这时直接在IDEA中运行Junit测试会出现上述错误。
**解决方法:**执行mvn test,测试生成编译文件
三、增删改查
数据库的功能在接口实现类Mapper.xml中实现
3.1 CRUD基础
在MyBatis程序中新增功能,需要修改三个文件:接口类、接口实现类、测试类
-
接口类
public interface UserMapper { List<User> getUserList(); User getUserById(int id); int addUser(User user); int deleteUserById(int id); int updateUser(User user); }
-
接口实现类
id:接口类中的方法名
resultType:Sql语句返回的结果类型
parameterType:接口定义返回参数的参数类型
<?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"> <!--namespace--> <mapper namespace="com.rainlx.dao.UserMapper"> <!--id中写的是接口类中的方法名,resultType中写的是下面sql语句返回的结果类型--> <!--select返回一个查询结果的List集合,集合的泛型是User类型--> <select id="getUserList" resultType="com.rainlx.pojo.User"> select * from test01.user </select> <select id="getUserById" resultType="com.rainlx.pojo.User" parameterType="int"> select * from test01.user where id = #{id} /*这里取id要通过#来取*/ </select> <insert id="addUser" parameterType="com.rainlx.pojo.User"> insert into test01.user (id, username, pwd) values (#{id},#{username},#{pwd}) </insert> <delete id="deleteUserById" parameterType="int"> delete from test01.user where id = #{id} </delete> <update id="updateUser" parameterType="com.rainlx.pojo.User"> update test01.user set username = #{username},pwd = #{pwd} where id = #{id} </update> </mapper>
-
测试类
“增删改”需要提交事务
public class UserDaoTest { @Test public void test(){ SqlSession session = MybatisUtils.getSqlSession(); UserMapper mapper = session.getMapper(UserMapper.class); List<User> userList = mapper.getUserList(); for (User user : userList) { System.out.println(user); } session.close(); //关闭SqlSession } @Test public void getUserById(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.getUserById(1); System.out.println(user); sqlSession.close(); } @Test public void insertUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.addUser(new User(4, "Aa", "666")); //“增删改”需要提交事务 sqlSession.commit(); sqlSession.close(); } @Test public void deleteUserById(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); int i = mapper.deleteUserById(4); sqlSession.commit(); sqlSession.close(); } @Test public void updateUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.updateUser(new User(3,"Bb","111222333")); sqlSession.commit(); sqlSession.close(); } }
3.2 Map
假设实体类的参数或数据库表中字段很多,可以使用Map
-
接口类
int updateUser2(Map<String,Object> map);
Map的语法:
Map<Key,Value>
-
接口实现类
接口实现类中,参数类型为map,SQL语句中包括需要修改的字段和主键即可
<update id="updateUser2" parameterType="map"> update test01.user set pwd = #{password} where id = #{id} /*这里的password和id是map的Key*/ </update>
-
测试类
@Test public void updateUser2(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Map<String, Object> map = new HashMap<>(); map.put("password",12321); map.put("id",3); mapper.updateUser2(map); sqlSession.commit(); sqlSession.close(); }
-
Map传递参数,直接在sql中取出Key
例如:
Map<String, Object> map = new HashMap<>(); map.put("pwd",12321); map.put("id",3); mapper.updateUser2(map);
-
对象传递参数,直接在sql中取出对象的属性
例如:
mapper.updateUser(new User(3,"Bb","111222333"));
-
只有一个基本类型参数的情况下,可以直接在sql中取到
例如:
mapper.deleteUserById(4);
-
多个参数用Map或者是注解
3.3 模糊查询
-
接口类
List<User> getUserListLike(String name);
-
接口实现类
<select id="getUserListLike" resultType="com.rainlx.pojo.User"> select * from test01.user where username like #{name} </select>
-
测试类
@Test public void getUserListLike(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> userListLike = mapper.getUserListLike("%m%"); //传递通配符% % for (User user:userListLike) { System.out.println(user); } sqlSession.close(); } 运行结果: User{id=1, username='admin', pwd='admin'} User{id=2, username='manager', pwd='123456'}
四、XML配置
4.1 核心配置文件
mybatis-config.xml文件,其顶层结构如下:
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
4.2 环境配置(environments)
MyBatis 可以配置成适应多种环境,可以将 SQL 映射应用于多种数据库之中。
连接N个数据库,就要创建N个SqlSessionFactory实例,每个数据库对应一个实例,为了制定创建哪种环境,只要将它作为可选的参数传递给 SqlSessionFactoryBuilder 即可。有下面两种方式:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);
环境配置中有两个重要的元素,事务管理器(transactionManager)和数据源(dataSource)
-
事务管理器(transactionManager)
在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]")
JDBC这个配置使用了JDBC的提交和回滚设施
- PS:如果使用 Spring + MyBatis,则没有必要配置事务管理器,因为 Spring 模块会使用自带的管理器来覆盖前面的配置。
-
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源
有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]")
- POOLED利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。
4.3 属性(properties)
可以在典型的Java属性文件中配置这些属性,也可以在properties元素的子元素中设置。编写好外部文件后,在核心配置文件中引入。
在外部文件中设置好的属性,可以用来替换需要动态配置的属性值,两种方式:
- 引入配置文件后,增加一些属性
<properties resource="org/mybatis/example/config.properties">
<property name="username" value="root"/>
<property name="password" value="root"/>
</properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
</dataSource>
</environment>
</environments>
- 直接引入外部配置文件
<!--引入外部配置文件-->
<properties resource="db.properties"/>
<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>
- 当外部文件和中存在相同字段时,优先使用外部配置文件的属性值。
4.4 设置(settings)
MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。
各项设置的含义可参考官方文档
4.5 类型别名(typeAliases)
可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
- 可以给实体类取别名
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
<typeAlias alias="Post" type="domain.blog.Post"/>
<typeAlias alias="Section" type="domain.blog.Section"/>
<typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>
这样配置后,Blog
可以用在任何使用domain.blog.Blog
的地方
- 也可以指定一个包名,这时可以直接使用小写字母来做别名,例如
<typeAliases>
<package name="domain.blog"/>
</typeAliases>
在包domain.blog
中的类domain.blog.Author
的别名为author,若有注解,则别名为其注解值,例如:
@Alias("author")
public class Author {
...
}
4.6 映射器(mappers)
定义 SQL 映射语句,告诉 MyBatis 到哪里去找到这些语句,在核心配置文件中添加绑定接口的语句。
- 方式一
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
- 方式二
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
- 方式三
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
其中,方式二和方式三要求,接口和Mapper配置文件必须同名,且必须在同一个包下。
五、 ResultMap结果集映射
解决类中属性名和数据库字段名不一致的问题
不一致时,直接执行查询,出现的结果为:
User{id=1, username='admin', password='null'}
因为根据password从数据库查询时,没有这个字段,所以取默认值null
- 解决方法:
用元素实现结果集映射
<resultMap id="UserMap" type="User">
<!--column对应数据库字段,property属性对应实体类的属性-->
<result column="id" property="id"/> <!--没有映射的可以不写-->
<result column="username" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
<select id="getUserById" resultMap="UserMap">
select * from test01.user where id =#{id}
</select>
注意,这里将resultType
属性替换掉了原来的 resultMap
属性
- ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了
六、日志
6.1 日志工厂
Mybatis 通过使用内置的日志工厂提供日志功能。内置日志工厂将会把日志工作委托给下面的实现之一:
- SLF4J
- Apache Commons Logging
- Log4j 2
- Log4j
- JDK logging
Mybatis内置日志工厂按照上面的顺序使用第一个查找到的实现。
如果想指定日志实现,可以在MyBatis 配置文件 mybatis-config.xml 里面添加一项 setting 来选择其它日志实现。可选的值有:SLF4J、LOG4J、LOG4J2、JDK_LOGGING、COMMONS_LOGGING、STDOUT_LOGGING、NO_LOGGING。
- 例:选择STDOUT_LOGGING为日志的实现
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
执行JDBC查询,日志结果如下:
6.2 日志配置
不同日志实现有不同的配置步骤,以Log4J为例。
步骤 1:添加 Log4J 包
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
步骤2:配置文件
在resources下建立一个log4j.properties文件
#设置
log4j.rootLogger = debug,stdout,D,E
#输出到控制台
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
#输出DEBUG级别以上的日志到
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = ./log/rainlx.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
#输出ERROR级别以上的日志到
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File = ./log/rainlx.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
步骤3:选择log4j为日志的实现
<settings>
<setting name="logImpl" value="Log4J"/>
</settings>
步骤4:测试日志实现
6.3 Log4j使用方法
步骤1:在需要使用Log4j的类包中导入log4j.jar包
import org.apache.log4j.Logger;
步骤2:生成日志对象
日志对象的参数为当前类的class
static Logger logger = Logger.getLogger(UserDaoTest.class);
步骤3:设置日志的级别
@Test
public void log4j(){
logger.info("信息级别");
logger.debug("调试级别");
logger.error("错误级别");
}
七、分页
7.1 SQL实现
语法:select * from test01.user limit startIndex,pageSize;
- 接口
List<User> limitUser(Map<String,Integer> map);
- Mapper
<!--这里用resultMap是因为使用了别名,否则需要使用全限定名-->
<select id="limitUser" parameterType="map" resultMap="UserMap">
select * from test01.user limit #{startIndex},#{pageSize}
</select>
- 测试
@Test
public void limitUser(){
SqlSession session = MybatisUtils.getSqlSession();
UserMapper mapper = session.getMapper(UserMapper.class);
HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("startIndex",0);
hashMap.put("pageSize",2);
List<User> userList = mapper.limitUser(hashMap);
for (User user : userList) {
System.out.println(user);
}
session.close();
}
7.2 Java实现
RowBounds
7.3 插件实现
PageHelper官网介绍了插件的使用方法
八、注解
MyBatis注解开发,可以映射简单语句,但稍复杂的语句,Java注解不太使用,最好使用XML映射语句。
8.1 注解开发
对于像 BlogMapper 这样的映射器类来说,还有另一种方法来完成语句映射。 它们映射的语句可以不用 XML 来配置,而可以使用 Java 注解来配置。
-
接口类
@Select("select * from test01.user") List<User> getUsers();
-
xml文件
<!--绑定接口--> <mappers> <mapper class="com.rainlx.dao.UserMapper"/> </mappers>
-
测试
@Test public void test(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> users = mapper.getUsers(); for (User user : users) { System.out.println(user); } sqlSession.close(); }
8.2 注解实现CRUD
SQL语句写在接口类中,然后在核心配置文件mybatis-config.xml中绑定接口文件,最后执行即可。
-
接口类
public interface UserMapper { //方法存在多个参数,所有的参数前必须加@Param("")注解 @Select("select * from test01.user where id = #{id}") User getUserById(@Param("id") int id); //values取的值必须为实体类中定义的参数名 @Insert("insert into test01.user(id,username,pwd) values (#{id},#{username},#{password})") int addUser(User user); @Update("update test01.user set username = #{username}, pwd = #{password} where id = #{id}") int updateUser(User user); //加了@Param注解之后,#取值的名字要和注解的名字相同 @Delete("delete from test01.user where id = #{delid}") int deleteUser(@Param("delid") int id); }
@Param()注解
- 基本类型的参数或者String类型,需要加
- 引用类型不加
- 如果只有一个基本类型,可以不加
- 加了之后,在SQL中使用的是注解中使用的属性名
-
测试
@Test public void getUserById(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User userById = mapper.getUserById(1); System.out.println(userById); sqlSession.close(); } @Test public void addUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.addUser(new User(6,"newuser", "123")); sqlSession.close(); } @Test public void updateUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.updateUser(new User(6,"updateuser", "111")); sqlSession.close(); } @Test public void deleteUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.deleteUser(6); sqlSession.close(); }
/*CRUD需要提交事务,但上面代码在执行CRUD之后没有commit,是因为将sqlSessionFactory中autocommit的值修改为了true*/ public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(true); }
九、Lombok
9.1 Lombok介绍
Lombok提供了一组注解,用来消除一些复杂的Java代码。提供的注解包括:
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@var
experimental @var
@UtilityClass
Lombok config system
Code inspections
Refactoring actions (lombok and delombok)
比较常用的:
@Data:提供无参构造、get、set、toString、hashcode、equals等方法
@NoArgsConstructor:提供无参构造方法
@AllArgsConstructor:提供有参构造方法
@ToString:提供toString方法
9.2 使用方法
-
Lombok插件安装:File→settings→Plugins,搜索Lombok进行安装。
-
导入依赖
Maven仓库查找相应的依赖并导入pom.xml中。
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> <scope>provided</scope> </dependency>
-
在实体类中添加注解
@Data @AllArgsConstructor @NoArgsConstructor public class User { private int id; private String username; private String password; }
这段代码相比下面这段不添加注解的代码,确实要简化很多,但代码的可阅读性不高,所以不不建议新手经常使用这类插件。
public class User { private int id; private String username; private String password; public User() { } public User(int id, String username, String password) { this.id = id; this.username = username; this.password = password; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } }
十、多表查询
10.1 多对一
数据库多表查询,查询每个学生对应的老师,设定现在有两张表student和teacher,student中有字段id、name、tid,其中tid为关联teacher的外键,teacher中有字段id、name。
方式一:按照查询嵌套处理
思路:1. 列出student中所有学生的信息
2. 根据查找到的tid去映射老师(子查询)
<select id="getStudent" resultMap="studentTeacher">
select * from student
</select>
<resultMap id="studentTeacher" type="Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!--复杂的属性单独处理
对象:association
集合:collection-->
<!--javaType设置对象teacher的类型,查询再嵌套一个select,即子查询-->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="Teacher">
select * from teacher where id = #{id}
</select>
方式二:按照结果嵌套处理
思路:SQL联表查询
<select id="getStudent2" resultMap="studentTeacher2">
select s.id sid,s.name sname,t.name tname
from student s,teacher t
where s.tid = t.id
</select>
<resultMap id="studentTeacher2" type="Student"> <!--查询结果实质上还是一个Student-->
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="Teacher"> <!--复杂映射用association-->
<result property="name" column="tname"/>
</association>
</resultMap>
10.2 一对多
查询一个老师下的所有学生信息
-
接口类
public interface TeacherMapper { Teacher getTeacher(@Param("tid") int id); }
-
实体类
@Data public class Teacher { private int id; private String name; private List<Student> students; }
方式一:按照结果嵌套处理
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid,s.name sname,t.id tid,t.name tname
from student s,teacher t
where s.tid = t.id and t.id = #{tid}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!--JavaType 指定属性的类型
ofType 集合中的泛型-->
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
方式二:按照查询嵌套处理
<select id="getTeacher2" resultMap="TeacherStudent2">
select * from teacher where id = #{tid}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTid" column="id"/>
</resultMap>
<select id="getStudentByTid" resultType="Student">
select * from student where tid = #{tid}
</select>
关键点
-
多对一,关联 - association
-
一对多,集合 - collection
-
“ofType” 属性,用来将 JavaBean(或字段)属性的类型和集合存储的类型区分开来。
<collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/>
读作: “posts 是一个存储 Post 的 ArrayList 集合”
“javaType”属性,用来指定实体类中属性的类型。
``
方式一:按照结果嵌套处理
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid,s.name sname,t.id tid,t.name tname
from student s,teacher t
where s.tid = t.id and t.id = #{tid}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!--JavaType 指定属性的类型
ofType 集合中的泛型-->
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
方式二:按照查询嵌套处理
<select id="getTeacher2" resultMap="TeacherStudent2">
select * from teacher where id = #{tid}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTid" column="id"/>
</resultMap>
<select id="getStudentByTid" resultType="Student">
select * from student where tid = #{tid}
</select>
关键点
-
多对一,关联 - association
-
一对多,集合 - collection
-
“ofType” 属性,用来将 JavaBean(或字段)属性的类型和集合存储的类型区分开来。
<collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/>
读作: “posts 是一个存储 Post 的 ArrayList 集合”
“javaType”属性,用来指定实体类中属性的类型。
以上内容是学习MyBatis的一些总结笔记,后续会更新Spring、Spring MVC、Spring Boot等内容的学习笔记。