目录
回顾mybatis环境搭建
- 首先创建一个maven项目,就一路next下去的那种即可;
- 然后在pom文件中引入几个依赖:
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.13</version>
</dependency>
<!--日志这个不是必要的-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
- 在Resource下创建SqlMapConfig.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="mysql">
<environment id="mysql">
<transactionManager type="jdbc"></transactionManager>
<!--数据库连接池-->
<dataSource type="POOLED">
<!--数据库连接配置-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/TestDB?serverTimezone=UTC"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="edu/xatu/Dao/UserDao.xml"></mapper>
</mappers>
</configuration>
- 将log4j.properties也放在Resource包下:
log4j.rootLogger=DEBUG, Console
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
- 然后在Java包下创建实体类,通过getter/setter方法生成,再重写toString即可;
package edu.xatu.Domain;
import java.io.Serializable;
import java.util.Date;
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String adress;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAdress() {
return adress;
}
public void setAdress(String adress) {
this.adress = adress;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", adress='" + adress + '\'' +
'}';
}
}
- 下一步创建一个接口
package edu.xatu.Dao;
//用户持久层
public interface UserDao {
//查询所有用户
List<User> findAll();
}
- 在Resource包下创建Java包下dao层路径相同一个UserDao.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="edu.xatu.mybatis.dao.UserDao" >
<select id="findAll" resultType="edu.xatu.mybatis.domain.mbuser">
select * from mbuser
</select>
</mapper>
- 最后创建一个测试类,为了今天的CRUD多个例子的测试,所以将重复的操作封装起来,通过@Before和@After注解让他们在各自的时间执行,这样在接下来的测试例子中就只需要关注单个操作的测试,而不用大量的重复代码了。
public class test01 {
private InputStream in;
private SqlSession session;
private UserDao userDao;
@Before//在测试方法执行之前执行
public void init() throws IOException {
//读取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//获取sqlsessionfactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//获取Session对象
session = factory.openSession();
//获取dao的代理对象
userDao = session.getMapper(UserDao.class);
}
//释放资源
@After//在测试方法执行之后进行
public void destroy() throws IOException {
//提交事务
session.commit();
session.close();
in.close();
}
/**
* 测试查询所有的操作
* @throws IOException
*/
@Test
public void testFindAll(){
//执行所有查询方法
List<User> users = userDao.findAll();
for(User user : users){
System.out.println(user);
}
}
}
好了,言归正传,接下来开始今天的重点CRUD的操作实现吧!
MyBatis的CRUD操作
其实在上面的环境搭建的代码中,很明显,已经写了一个查询所有的方法在里面了......
然后,在上面这种环境搭建成功的基础上,再实现CRUD就很简单了,只需要在三个文件里动动手脚就能搞定啦!
(1)在UserDao接口中定义一个方法;
(2)UserDao.xml文件的mapper标签中定义需要的sql语句;
(3)然后,编写单元测试方法
例如,增加操作
在UserDao接口定义增加一个用户的方法
//增加一个用户
void insertUser(User user);
在UserDao.xml中定sql语句
<!--插入新用户 保存用户 parameterType参数的类型-->
<insert id="saveUser" parameterType="edu.xatu.Domain.User">
insert into mbuser(username,adress,birthday,sex) values(#{username},#{adress},#{birthday},#{sex});
</insert>
在test中编写测试方法进行增加一个用户的单元测试
/**
* 测试增加用户操作
*/
@Test
public void testInsertUser(){
User user = new User();
user.setUsername("肖战");
user.setAdress("湖南省长沙市");
user.setBirthday(new Date());
user.setSex("男");
userDao.saveUser(user);
}
不信你去看看你的数据库表,有木有新增一条记录吖
好啦好啦,CRUDCRUD啦
UserDao接口(全部操作的代码):
package edu.xatu.Dao;
import edu.xatu.Domain.Queryvo;
import edu.xatu.Domain.User;
import java.util.List;
/**
* 用户持久层
*/
public interface UserDao {
//查询所有用户
List<User> findAll();
//保存用户
void saveUser(User user);
//更新用户
void updateUser(User user);
//删除用户
void deleteUser(Integer id);
//根据id查询用户
User findbyId(Integer userId);
//根据名称模糊查询
List<User> findbyName(String userName);
//查询总用户数
int findTotal();
//根据queryvo中的条件查询用户
List<User> findbyQuery(Queryvo vo);
}
UserDao.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="edu.xatu.Dao.UserDao">
<select id="findAll" resultType="edu.xatu.Domain.User">
select * from mbuser
</select>
<!--插入新用户 保存用户 parameterType参数的类型-->
<insert id="saveUser" parameterType="edu.xatu.Domain.User">
<!--配置插入操作之后,获取插入数据的id-->
<selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
insert into mbuser(username,adress,birthday,sex) values(#{username},#{adress},#{birthday},#{sex});
</insert>
<!--更新用户-->
<update id="updateUser" parameterType="edu.xatu.Domain.User">
update mbuser set username=#{username},adress=#{adress},birthday=#{birthday},sex=#{sex} where id=#{id}
</update>
<!--删除用户-->
<!--删除方法parameterType属性为基本数据类型或者基本数据类型的包装类时,且sql语句中只传一个值,这里占位符写什么都可以-->
<delete id="deleteUser" parameterType="Integer">
delete from mbuser where id=#{suiyixie}
</delete>
<!--根据id查询用户-->
<select id="findbyId" parameterType="Integer" resultType="edu.xatu.Domain.User">
select * from mbuser where id=#{suiyi}
</select>
<!--根据名称模糊查询-->
<select id="findbyName" parameterType="String" resultType="edu.xatu.Domain.User" >
<!-- 这里没有%时,在测试方法就必须写%-->
select * from mbuser where username like #{name}
<!--select * from mbuser where username like '%${value}%'-->
</select>
<!--获取用户总记录条数-->
<select id="findTotal" resultType="int">
select count(id) from mbuser;
</select>
<!--根据queryvo条件查询用户-->
<select id="findbyQuery" parameterType="edu.xatu.Domain.Queryvo" resultType="edu.xatu.Domain.User">
select * from mbuser where username like #{user.username}
</select>
</mapper>
单元测试方法(全部操作的测试方法)
package edu.xatu.Test;
import edu.xatu.Dao.UserDao;
import edu.xatu.Domain.Queryvo;
import edu.xatu.Domain.User;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
/**
* 测试mybatis的CRUD操作
*/
public class test01 {
private InputStream in;
private SqlSession session;
private UserDao userDao;
//定义重复操作
@Before//在测试方法执行之前执行
public void init() throws IOException {
//读取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//获取sqlsessionfactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//获取Session对象
session = factory.openSession();
//获取dao的代理对象
userDao = session.getMapper(UserDao.class);
}
//释放资源
@After//在测试方法执行之后进行
public void destroy() throws IOException {
//提交事务
session.commit();
session.close();
in.close();
}
/**
* 测试查询所有的操作
* @throws IOException
*/
@Test
public void testFindAll(){
//执行所有查询方法
List<User> users = userDao.findAll();
for(User user : users){
System.out.println(user);
}
}
/**
* 测试增加用户操作
*/
@Test
public void testSave(){
User user = new User();
user.setUsername("肖战");
user.setAdress("湖南省长沙市");
user.setBirthday(new Date());
user.setSex("男");
System.out.println("操作前"+user);
//只需要保存操作的代码即可
userDao.saveUser(user);
System.out.println("操作后"+user);
}
/**
* 测试更新用户的操作
*/
@Test
public void testUpdate(){
User user = new User();
user.setId(2);
user.setUsername("华晨宇");
user.setAdress("四川省成都市");
user.setBirthday(new Date());
user.setSex("男");
userDao.updateUser(user);
}
/**
* 测试删除用户的操作
*/
@Test
public void testDelete(){
userDao.deleteUser(1);
}
/**
* 测试根据id查询用户操作
*/
@Test
public void testFindById(){
User user = userDao.findbyId(3);
System.out.println(user);
}
/**
* 测试模糊查询
*/
@Test
public void testfindbyName(){
List<User> user = userDao.findbyName("%华%");
// List<User> user = userDao.findbyName("华");
for(User users : user){
System.out.println(users);
}
}
/**
* 测试用户条数
*/
@Test
public void testfindTotal(){
int count = userDao.findTotal();
System.out.println(count);
}
/**
* 测试模糊查询
*/
@Test
public void testfindbyQuery(){
Queryvo vo = new Queryvo();
User user = new User();
user.setUsername("%毛%");
vo.setUser(user);
List<User> users = userDao.findbyQuery(vo);
for(User u : users){
System.out.println(u);
}
}
}
配置文件参数
在上面的增加操作中有个问题啊,如果我想新增一条记录后,获取新增的这条记录的id应该怎么操作呢?selectKey了解一下啦~
<insert id="saveUser" parameterType="edu.xatu.Domain.User">
<!--配置插入操作之后,获取插入数据的id-->
<selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
insert into mbuser(username,adress,birthday,sex) values(#{username},#{adress},#{birthday},#{sex});
</insert>
要不测试一下你康康?
呶,这不获取到了id=6! 小小标签,作用倒是一堆,了不起了不起,保温杯里泡枸杞......
1. properties属性
在SqlMapConfig.xml中,其实阔以这样,对比上面的SqlMapConfig.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="jdbcConfig.properties">
<property name="driver" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/TestDB?serverTimezone=UTC"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</properties>
<!--环境配置-->
<environments default="mysql">
<environment id="mysql">
<transactionManager type="jdbc"></transactionManager>
<!--数据库连接池-->
<dataSource type="POOLED">
<!--数据库连接配置-->
<property name="driver" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>
</dataSource>
</environment>
</environments>
<mappers>
<!--<mapper resource="edu/xatu/Dao/UserDao.xml"></mapper>-->
<!--package用于指定dao接口所在的包,当指定完成之后就不需要写mapper-->
<package name="edu.xatu.Dao"></package>
</mappers>
</configuration>
找到区别了吧,嘻嘻~ 这时候你可能说,吃饱了撑的,写在环境配置里不香么,你挪上去干啥 ?!撑的
这样写我......确实撑的,其实啦
properties可以将数据库连接参数单独配置在jdbcConfig.properties(名字不重要)中,放在类路径下。这样只需要在SqlMapConfig.xml中加载jdbcConfig.properties的属性值。这样在SqlMapConfig.xml中就不需要对数据库连接参数硬编码。将数据库连接参数只配置在jdbcConfig.properties中,这样一来方便对参数进行统一管理,其它xml可以引用该jdbcConfig.properties,例如:
在Resource包下写了jdbcConfig.properties文件
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/TestDB?serverTimezone=UTC
user=root
password=123456
在SqlMapConfig.xml中通过properties读取资源即可
<properties resource="jdbcConfig.properties"></properties>
2. environments
MyBatis 可以配置多种环境。这会帮助你将 SQL 映射应用于多种数据库之中。但是你可以配置多种环境,但每个数据库对应一个 SqlSessionFactory。所以,如果你想连接两个数据库,你需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。
- 用environment 的id属性来标识,然后environments 的default指定
这块不想贴例子了,就给啥名就调用啥名也就是用的此种环境配置了
3. typeAliases
typeAliases可以用来自定义别名,需要parameterType指定输入参数的类型、需要resultType指定输出结果的映射类型。如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在配置文件中通过别名定义,方便开发。
(typeAliases配置别名,type属性指定的是实体类全限定名,alies属性指定别名,当指定了别名就不再区分大小写)
<typeAliases>
<typeAlias type="edu.xatu.Domain.User" alias="user"></typeAlias>
<!--用于配置要指定别名的包,当指定后,该包下的实体类都会被注册别名,而且类名就是别名,不再区分大小写-->
<package name="edu.xatu.Domain"></package>
</typeAliases>
4. typeHandlers
mybatis中通过typeHandlers完成jdbc类型和java类型的转换。通常情况下,mybatis提供的类型处理器满足日常需要,不需要自定义。具体可参考Mybatis的官方文档。
5. Mappers (映射器)
Mapper配置的几种方法:
第一种
<mapper resource=" " /> resource指向的是相对于类路径下的目录
如:<mapper resource="sqlmap/User.xml" />
第二种
<mapper url=" " /> 使用完全限定路径
如:<mapper url="file:///D:\workspace\mybatis1\config\sqlmap\User.xml" />
第三种
<mapper class=" " /> 使用mapper接口类路径
如:<mapper class="cn.kang.mapper.UserMapper"/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
第四种
<package name=""/> 注册指定包下的所有mapper接口
如:<package name="cn.kang.mapper"/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
6.Mapper 映射文件
Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心
Mapper映射文件是一个xml格式文件,必须遵循相应的dtd文件规范
Mapper映射文件是以<mapper>作为根节点,在根节点中支持9个元素,分别为insert、update、delete、select(增删改查);cache、cache-ref、resultMap、parameterMap、sql
7. select
(1)id (必须配置)
id是命名空间中的唯一标识符,可被用来代表这条语句。
一个命名空间(namespace) 对应一个dao接口, 这个id也应该对应dao里面的某个方法(相当于方法的实现),因此id 应该与方法名一致。
(2)parameterType (可选配置, 默认为mybatis自动选择处理)
将要传入语句的参数的完全限定类名或别名, 如果不配置,mybatis会通过ParameterHandler 根据参数类型默认选择合适的typeHandler进行处理,parameterType 主要指定参数类型,可以是int, short, long, string等类型,也可以是复杂类型。
(3)resultType (resultType 与 resultMap 二选一配置)
resultType用以指定返回类型,指定的类型可以是基本类型,可以是java容器,也可以是javabean。
(4)resultMap (resultType 与 resultMap 二选一配置)
resultMap用于引用我们通过 resultMap标签定义的映射类型,这也是mybatis组件高级复杂映射的关键。
(5)flushCache (可选配置)
将其设置为 true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值:false 。
(6)statementType (可选配置)
STATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
(7)resultSetType (可选配置)
FORWARD_ONLY,SCROLL_SENSITIVE 或 SCROLL_INSENSITIVE 中的一个,默认值为 unset (依赖驱动)。
8. parameterType(输入类型)
通过parameterType指定输入参数的类型,类型可以是简单类型、hashmap、pojo的包装类型。
#{}实现的是向prepareStatement中的预处理语句中设置参数值,sql语句中#{}表示一个占位符即?。
(1)parameterType也可以传递pojo对象。Mybatis使用ognl表达式解析对象字段的值。
(2)parameterType也可以传递hashmap类型的参数
9. resultType(返回值类型)
使用resultType可以进行输出映射,只有查询出来的列名和pojo中的属性名一致,才可以映射成功。如果查询出来的列名和pojo中的属性名全部不一致,就不会创建pojo对象。但是只要查询出来的列名和pojo中的属性有一个一致,就会创建pojo对象。
10. resultMap(输出结果映射)
mybatis中可以使用resultMap完成高级输出结果映射。如果查询出来的列名和定义的pojo属性名不一致,就可以通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。然后使用resultMap作为statement的输出映射类型。resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询。
11. Plugins (插件)
啥都先别说,来个例子你就明白了:
<!-- 配置分页插件 -->
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<!-- 设置数据库类型 Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL六种数据库-->
<property name="dialect" value="mysql"/>
</plugin>
</plugins>