一、前置工作
1.1 MyBatis简介
- MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。
- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
- MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO为数据库中的记录。
- 官方文档:https://mybatis.org/mybatis-3/zh/index.html
1.2 个人点评分析
- MyBatis是一款优秀的持久层框架,通俗来说就是用来连接数据库。在没有JPA和MyBatis之前,原生JDBC式操作设置参数和获取结果集的工作非常臃肿枯燥。
- 在MyBatis中可以通过简单的 XML或者Java注解实现JDBC大量代码才能完成的操作。
- MyBatis简单易学,不需要第三方依赖,只需要看官方文档就可以学习。
- MyBatis将SQL语句放到XML文件内,统一管理和优化。SQL作为数据库领域的霸主,基本可以实现我们所有的功能,而MyBatis可以很方便使用原生SQL。
- 高内聚低耦合,SQL不放在Dao,使得系统设计清晰,而JPA没有做到这一点
- 在最近参与的项目编写中,采用了Xboot框架,其中整合了MyBatis和JPA。从实际使用性来说,MyBatis的优势远远大于JPA。
1.3 idea新建项目配置
- jdk 11.0.6
- maven 3.6.2 阿里云
- idea 2019.3
- 选择创建maven新项目,删除src目录,创建子module
- 在 File | Settings | Build, Execution, Deployment | Build Tools | Maven 中,配置maven
- 在 File | Settings | Build, Execution, Deployment | Compiler | Java Compiler 中,设置发行版本为 11
- File | Settings | Editor | File Encodings,编码改为UTF-8
- 在File | Project Setting | Modules 中,将版本设置为11
1.4 依赖、资源过滤
放在父 pom.xml 中即可
<properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</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> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.0</version> </dependency> </dependencies> <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>
1.5 创建数据库
因为关联外键、异步等原因,必须分步执行,否则会出错
CREATE DATABASE `test`; USE `test` CREATE TABLE `user`( `id` VARCHAR(50) NOT NULL, `name` VARCHAR(10) DEFAULT NULL, `age` INT(10) DEFAULT NULL, PRIMARY KEY (`id`) )ENGINE=INNODB DEFAULT CHARSET=UTF8; CREATE TABLE `teacher`( `id` VARCHAR(50) NOT NULL, `name` VARCHAR(10) DEFAULT NULL, PRIMARY KEY (`id`) )ENGINE=INNODB DEFAULT CHARSET=utf8 CREATE TABLE `student`( `id` VARCHAR(50) NOT NULL, `name` VARCHAR(10) DEFAULT NULL, `teacher` VARCHAR(50) DEFAULT NULL , PRIMARY KEY (`id`), FOREIGN KEY(`teacher`) REFERENCES teacher(id) )ENGINE=INNODB DEFAULT CHARSET=utf8 create table `book`( `id` varchar(50) primary key, `name` varchar(20) default null, `money` double default 0.0, `buy_date` datetime )engine=InnoDB default charset=utf8 INSERT INTO `user`(`id`,`name`,`age`) VALUES (0,"ZWZ01","123456"), (1,"ZWZ02","123456"), (2,"ZWZ03","123456"); INSERT INTO `teacher`(`id`,`name`) VALUES (1,'ZWZ'); INSERT INTO `student`(`id`,`name`,`teacher`) VALUES (1,'ZWZ01',1); INSERT INTO `student`(`id`,`name`,`teacher`) VALUES (2,'ZWZ02',1); INSERT INTO `student`(`id`,`name`,`teacher`) VALUES (3,'ZWZ03',1); INSERT INTO `student`(`id`,`name`,`teacher`) VALUES (4,'ZWZ04',1); INSERT INTO `student`(`id`,`name`,`teacher`) VALUES (5,'ZWZ05',1);
1.6 idea连接MySQL
设置时区后,点击 Test Connection
属性 | 值 |
serverTimezone | Asia/Shanghai |
二、增删改查
2.1 公用类
数据库配置
db.properties,用于连接数据库的重要信息,一般为驱动名、URL地址、用户名、密码
driver=com.mysql.jdbc.Driver url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false username=root password=123456
mybatis配置
mybatis-config.xml,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> <properties resource="db.properties"/> <settings> <!--开启日志--> <setting name="logImpl" value="STDOUT_LOGGING"/> <!--驼峰转换--> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> <typeAliases> <package name="zwz.pojo"/> </typeAliases> <environments default="zwz"> <environment id="zwz"> <transactionManager type="JDBC"></transactionManager> <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 class="zwz.mapper.UserMapper"/> </mappers> </configuration>
实体类
用户类User,包含id、name、age三个变量,其中Id由工具类 IdUtils 自动生成
@Data @AllArgsConstructor @NoArgsConstructor public class User { private String id; private String name; private int age; }
SqlSession工具类
- 用于获取session对象
- 先从 SqlSessionFactoryBuilder 工厂构造器构建SqlSessionFactory
- 再从SqlSessionFactory工厂生产SqlSession
- 为了简化代码,封装成一个工具类
public class MybatisUtils { private static SqlSessionFactory sqlSessionFactory; static { try { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(); } }
随机ID工具类
该类用于随机生成ID,其中横线被替换为空,也可以替换成其他值
public class IdUtils { public static String getId(){ return UUID.randomUUID().toString().replaceAll("-",""); } }
2.2 增加用户
mapper层接口
要实现增加用户,第一步先写一个接口,在用XML具体实现这个接口
public interface UserMapper { // 增加用户 int addUser(User user); }
XML具体实现
- namespace是命名空间,必须和接口的地址相对应
- id为接口方法名,必须对应
- parameterType为传入参数类型,因为已配置别名,一般使用首字母小写的类名
- #{}中的字符串,要和实体类变量名对应,或用resultMap
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="zwz.mapper.UserMapper"> <insert id="addUser" parameterType="user"> insert into user(id, name, age) VALUES (#{id},#{name},#{age}); </insert> </mapper>
Insert, Update, Delete 元素的属性如下
属性 | 描述 |
id |
在命名空间中唯一的标识符,可以被用来引用这条语句。 |
parameterType |
将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。 |
parameterMap |
用于引用外部 parameterMap 的属性,目前已被废弃。请使用行内参数映射和 parameterType 属性。 |
flushCache |
将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:(对 insert、update 和 delete 语句)true。 |
timeout |
这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。 |
statementType |
可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。 |
useGeneratedKeys |
(仅适用于 insert 和 update)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false。 |
keyProperty |
(仅适用于 insert 和 update)指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset )。如果生成列不止一个,可以用逗号分隔多个属性名称。 |
keyColumn |
(仅适用于 insert 和 update)设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。 |
databaseId |
如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。 |
测试
- 测试方法中,增加了六个用户
- 增删改操作之后必须提交事务,否则无效
/** * 增加用户 */ @Test public void testAddUser(){ SqlSession session = MybatisUtils.getSqlSession(); UserMapper mapper = session.getMapper(UserMapper.class); mapper.addUser(new User(IdUtils.getId(),"ZWZ1",18)); mapper.addUser(new User(IdUtils.getId(),"ZWZ2",18)); mapper.addUser(new User(IdUtils.getId(),"ZWZ3",18)); mapper.addUser(new User(IdUtils.getId(),"ZWZ4",18)); mapper.addUser(new User(IdUtils.getId(),"ZWZ5",18)); mapper.addUser(new User(IdUtils.getId(),"ZWZ6",18)); session.commit(); session.close(); }
日志输出
可以看到,系统执行了六次insert SQL语句,成功插入
Created connection 1552326679. Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@5c86a017] ==> Preparing: insert into user(id, name, age) VALUES (?,?,?); ==> Parameters: 9e3eed6af6da4214b520535cac13f13a(String), ZWZ1(String), 18(Integer) <== Updates: 1 ==> Preparing: insert into user(id, name, age) VALUES (?,?,?); ==> Parameters: 7322170480104981a58b28f51fdb2288(String), ZWZ2(String), 18(Integer) <== Updates: 1 ==> Preparing: insert into user(id, name, age) VALUES (?,?,?); ==> Parameters: f0d102cd857645c9aaca4ded53abb0e8(String), ZWZ3(String), 18(Integer) <== Updates: 1 ==> Preparing: insert into user(id, name, age) VALUES (?,?,?); ==> Parameters: e4993aecfd4f4322905eb6dc0cf039b9(String), ZWZ4(String), 18(Integer) <== Updates: 1 ==> Preparing: insert into user(id, name, age) VALUES (?,?,?); ==> Parameters: 4e387cafc50840468c4dfeec54940e1c(String), ZWZ5(String), 18(Integer) <== Updates: 1 ==> Preparing: insert into user(id, name, age) VALUES (?,?,?); ==> Parameters: 35ee11b46afa47a68be7713ecdeccd7e(String), ZWZ6(String), 18(Integer) <== Updates: 1 Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@5c86a017] Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@5c86a017] Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@5c86a017] Returned connection 1552326679 to pool. Process finished with exit code 0