目录
模块一:快速入门
1.创建数据库,插入数据
2.创建maven模块后,需要导入的依赖有哪些?
3.想要输出查询到的数据(包括日志打印),需要创建哪些文件?
4.如何放置UserMapper接口与User类?
5.如何放置UserMapper.xml配置文件?
6.在UserMapper.xml文件中需要写什么内容?
7.mybatis-config.xml,logback.xml的文件位置在哪里?在mybatis-config.xml中需要配置什么?
8.写测试方法,主要内容为调用mapper接口中的方法,完成对表的查询操作
模块二:增删改查
安装MyBatisX插件点击鸟就能自动跳转
准备数据
按照模块一再次创建工程,主要实验内容模块有:BrandMapper.xml,BrandMapper接口,App实验类。配置pom文件,mybatis-congfig.xml,logback.xml文件可复制粘贴
对于Brand实体类有部分内容需要快速构造,故增添了数个构造方法
0.在mapper.xml配置文件中如何简化增删改查标签中的全类名?
1..查询所有:实体类的属性与表的列名冲突不一样时,mybatis封装数据会出现什么问题?该如何解决?
2.单条件查询:如何根据传入的单个条件查询数据?
3.如何通过注解来给接口传递简单的sql语句(不写mapper.xml文件)?
4.多条件查询的Mapper接口中能够能够传递哪些数据?各有什么特点?多条件查询中,如有为null的数据,该查询将会如何执行?
5.如何实现动态的多条件查询(有查询条件则查询,为0~n个或者0~1个,条件为空就不查询),对于传递的字符串数据应该注意什么?
6.如何实现添加数据?添加数据等需要修改数据库表的内容的操作需要如何提交事务?
7.如何在添加数据之后快速获得该数据自动增长的id?
8..如何实现修改数据?修改数据能自动返回什么消息?
9.传递数据为空的话数据也会修改吗?如何实现动态修改数据?
10.根据id实现批量删除数据可向接口中传递数组,如何实现批量删除?
删除单个:
批量删除:
11.mapper接口中传入的参数不同,对应在mapper.xml文件中引用该参数应该如何描述?
模块一:快速入门
目标:查询USER表中的所有数据(以下内容有部分操作为非必要操作,有其余更多的解决方案,提出的问题仅用于加深记忆)
1.创建数据库,插入数据
drop table if exists tb_user;
create table tb_user(
id int primary key auto_increment,
username varchar(20),
password varchar(20),
gender char(1),
addr varchar(30)
);
INSERT INTO tb_user VALUES (1, 'zhangsan', '123', '男', '北京');
INSERT INTO tb_user VALUES (2, '李四', '234', '女', '天津');
INSERT INTO tb_user VALUES (3, '王五', '11', '男', '西安');
2.创建maven模块后,需要导入的依赖有哪些?
1.mybatis
2.mysql-connector-java(用于连接数据库)
3.logback-classic(用于打印日志,mybatis自动适配,不必要)
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
3.想要输出查询到的数据(包括日志打印),需要创建哪些文件?
1.mybatis-config.xml,logback.xml
2.UserMapper.xml
3.UserMapper接口,User类,实验类
4.如何放置UserMapper接口与User类?
分别在pojo包与mapper包中创建pojo类User 与mapper接口UserMapper
mapper接口中需要用到的方法如下(查询所有用户)
public interface UserMapper {
List<User> selectAll();
}
public class User {
private Integer id;
private String username;
private String password;
private String gender;
private String addr;
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", gender='" + gender + '\'' +
", addr='" + addr + '\'' +
'}';
}
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 String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
}
5.如何放置UserMapper.xml配置文件?
建立UserMapper.xml文件,放在和接口同名的resources/org/example/mapper目录下
此时可以使用package指令打包项目:可以在mapper包下发现了接口与xml配置文件。
6.在UserMapper.xml文件中需要写什么内容?
这个文件相当于为指定的mapper接口写具体实现,主要内容是写sql语句,还需要指定对应的接口(是哪一个mapper)与返回数据的类型(是哪一个pojo)
<?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属性为对应需要实现的接口的全类名-->
<mapper namespace="org.example.mapper.UserMapper">
<!--该标签表示查询命令,属性指定返回数据的类型-->
<select id="selectAll" resultType="org.example.pojo.User">
select * from tb_user;
</select>
</mapper>
7.mybatis-config.xml,logback.xml的文件位置在哪里?在mybatis-config.xml中需要配置什么?
文件位置在工程的resource目录下
在mybatis-config.xml的configuration标签中需要配置环境连接数据库与指定mapper.xml的位置。
logback.xml:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%level] %boldGreen(%logger{15}) - %msg %n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="Console"/>
</root>
</configuration>
mybatis-config.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--连接数据库,可以写多个environment来配置多个数据库,default属性切换不同的environment-->
<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:///db1?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///db1?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--指定mapper.xml配置文件的位置,包扫描-->
<mappers>
<package name="org.example.mapper"/>
</mappers>
</configuration>
工程详细目录:
8.写测试方法,主要内容为调用mapper接口中的方法,完成对表的查询操作
public class App
{
public static void main( String[] args ) throws IOException {
//1.加载mybatis核心配置文件
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
//2.获取sqlsession对象
SqlSession sqlSession=sqlSessionFactory.openSession();
//3.获取接口,调用其方法执行sql
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
userMapper.selectAll().forEach(System.out::println);
//4.释放资源
sqlSession.close();
}
}
模块二:增删改查
安装MyBatisX插件点击鸟就能自动跳转
准备数据
drop table if exists tb_brand;
create table tb_brand
(
id int primary key auto_increment,
brand_name varchar(20),
company_name varchar(20),
ordered int,
description varchar(100),
status int
);
insert into tb_brand (brand_name, company_name, ordered, description, status)
values ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),
('华为', '华为技术有限公司', 100, '华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界', 1),
('小米', '小米科技有限公司', 50, 'are you ok', 1);
SELECT * FROM tb_brand;
按照模块一再次创建工程,主要实验内容模块有:BrandMapper.xml,BrandMapper接口,App实验类。配置pom文件,mybatis-congfig.xml,logback.xml文件可复制粘贴
对于Brand实体类有部分内容需要快速构造,故增添了数个构造方法
public class Brand {
private Integer id;
private String brandName;
private String companyName;
private Integer ordered;
private String description;
private Integer status;
public Brand() {
}
public Brand(String brandName, String companyName, Integer status) {
this.brandName = brandName;
this.companyName = companyName;
this.status = status;
}
public Brand(String brandName, String companyName, Integer ordered, String description, Integer status) {
this.brandName = brandName;
this.companyName = companyName;
this.ordered = ordered;
this.description = description;
this.status = status;
}
public Brand(Integer id, String brandName, String companyName, Integer ordered, String description, Integer status) {
this.id = id;
this.brandName = brandName;
this.companyName = companyName;
this.ordered = ordered;
this.description = description;
this.status = status;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getBrandName() {
return brandName;
}
public void setBrandName(String brandName) {
this.brandName = brandName;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public Integer getOrdered() {
return ordered;
}
public void setOrdered(Integer ordered) {
this.ordered = ordered;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
@Override
public String toString() {
return "Brand{" +
"id=" + id +
", brandName='" + brandName + '\'' +
", companyName='" + companyName + '\'' +
", ordered=" + ordered +
", description='" + description + '\'' +
", status=" + status +
'}';
}
}
0.在mapper.xml配置文件中如何简化增删改查标签中的全类名?
在mybatis-config.xml中起别名(标签的前后顺序有要求)
<configuration>
<!--在此处加上该标签可起别名,在mapper.xml文件中type属性可以不使用全类名-->
<typeAliases>
<package name="org.example.pojo"/>
</typeAliases>
<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:///db1?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="org.example.mapper"/>
</mappers>
</configuration>
下列案例的代码顺序:mapper.xml-mapper-实验类
1..查询所有:实体类的属性与表的列名冲突不一样时,mybatis封装数据会出现什么问题?该如何解决?
实体类的属性与表的列名冲突不一样时,mybatis不能自动封装数据,导致查询结果某列为null 比如mysql表的列名为brand_name,java类中变量名为brandName
Mapper.xml:
<!--1.1无法查询完整的数据的写法-->
<select id="selectAll1" resultType="Brand">
select * from tb_brand;
</select>
<!--
1.2能够查询完整数据的写法:对sql表与java类中名称不同的属性做映射
resultMap标签中的属性:
需要指定id(唯一标识),在后续标签中返回中会用到,代替原本的resultType
需要指定返回的实体类type(可以使用别名)
内部的标签:
需要指定是主键还是其它键
<id>标签是主键的映射,<result>标签是其他键的映射
需要指定表的列名与实体类中的属性名
column是表的列名,property是Java类中的属性名
-->
<resultMap id="brandResultMap" type="Brand">
<id column="id" property="id"/>
<result column="brand_name" property="brandName"/>
<result column="company_name" property="companyName"/>
</resultMap>
<select id="selectAll2" resultMap="brandResultMap">
select * from tb_brand;
</select>
Mapper接口:
List<Brand> selectAll1();
List<Brand> selectAll2();
实验类:
@Test
public void selectAll() throws IOException {
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession sqlSession=sqlSessionFactory.openSession();
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
System.out.println("未做映射的输出:");
brandMapper.selectAll1().forEach(System.out::println);
System.out.println("做映射后的输出:");
brandMapper.selectAll2().forEach(System.out::println);
sqlSession.close();
}
2.单条件查询:如何根据传入的单个条件查询数据?
使用#{name}代表接口中传入的数据,也可以使用${name} 前者将对数据进行处理(如防止sql注入,或给模糊查询中的数据自动封装双引号......) 后者则把数据原封不动传入标签中的sql语句(本工程中无此案例)。 使用大于小于符号时可以使用转义符(如<)
<select id="selectById" resultMap="brandResultMap">
select * from tb_brand where id = #{id};
</select>
Brand selectById(int id);
@Test
public void selectById() throws IOException {
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession sqlSession=sqlSessionFactory.openSession();
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
System.out.println(brandMapper.selectById(1));
sqlSession.close();
}
3.如何通过注解来给接口传递简单的sql语句(不写mapper.xml文件)?
注解中的内容与mapper.xml文件中的内容一致 由于不会使用到mapper.xml文件中的属性,无法引用配置文件中的resultMap 映射类的属性与数据表的列名可以使用Results注解
@Select("select * from tb_brand where id=#{id};")
@Results(id="resultMap",value = {
@Result(column = "brand_name",property = "brandName"),
@Result(column = "company_name",property = "companyName"),
})
Brand selectById2(int id);
@Test
public void selectById2() throws IOException {
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession sqlSession=sqlSessionFactory.openSession();
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
System.out.println(brandMapper.selectById2(1));
sqlSession.close();
}
4.多条件查询的Mapper接口中能够能够传递哪些数据?各有什么特点?多条件查询中,如有为null的数据,该查询将会如何执行?
多条件查询,在mapper接口中能有多种方法(重载)去传递信息,在映射文件中只写一个查询语句
<select id="selectByCondition" resultMap="brandResultMap">
select * from tb_brand
where status=#{status}
and company_name like #{companyName}
and brand_name like #{brandName};
</select>
多条件查询接口1:传递多个参数
不写注解会报错,这里的注解名对应的是mapper.xml中#{}内的内容
如果传递多个参数,mybatis会创建map集合封装
不使用注解的话,mapper.xml文件中#{}内就只能用arg0~n和param1~n
List<Brand> selectByCondition( @Param("status")int status, @Param("companyName")String companyName, @Param("brandName")String brandName);
多条件查询接口2:传递实体类对象
映射文件里面找哪个值就去给他的对象的那个方法里面找对应的get方法
List<Brand> selectByCondition(Brand brand);
多条件查询接口3:传递Map
键对应类的属性(mapper.xml中#{}内的内容),值对应数据
List<Brand> selectByCondition(Map map);
@Test
public void selectByCondition() throws IOException {
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession sqlSession=sqlSessionFactory.openSession();
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
System.out.println("1.通过传递多个参数查询数据");
System.out.println(brandMapper.selectByCondition(0,"%三%","%三%"));
System.out.println("2.通过传递对象查询数据");
System.out.println(brandMapper.selectByCondition(new Brand("%三%","%三%",0)));
System.out.println("3.通过传递Map查询数据");
HashMap<String,Object> hashMap = new HashMap<>();
hashMap.put("status",0);
hashMap.put("companyName","%三%");
hashMap.put("brandName","%三%");
System.out.println(brandMapper.selectByCondition(hashMap));
System.out.println("4.缺少数据将会导致查询失误,为空的条件也将会被列入查询条件中");
System.out.println(brandMapper.selectByCondition(0,"%三%",null));
sqlSession.close();
}
5.如何实现动态的多条件查询(有查询条件则查询,为0~n个或者0~1个,条件为空就不查询),对于传递的字符串数据应该注意什么?
使用where+choose+when标签,查询条件有0~1个 where可以去除choose标签中使用otherwise标签写1=1的情况,去除where会报错<select id="selectByCondition2" resultMap="brandResultMap"> select * from tb_brand <where> <if test="status!=null"> and status=#{status} </if> <if test="companyName!=null and companyName!=''"> and company_name like #{companyName} </if> <if test="brandName!=null and brandName!=''"> and brand_name like #{brandName} </if> </where> </select>
使用where标签与if标签,查询条件为0~n个 where去除第一个条件“1=1” 需要注意字符串可以为''和null的两种情况<select id="selectByCondition3" resultMap="brandResultMap"> select * from tb_brand <where> <choose> <when test="status!=null"> status=#{status} </when> <when test='companyName!=null and companyName!=""'> company_name like #{companyName} </when> <when test="brandName!=null and brandName!=''"> brand_name like #{brandName} </when> </choose> </where> </select>
List<Brand> selectByCondition2(
@Param("status")int status,
@Param("companyName")String companyName,
@Param("brandName")String brandName);
List<Brand> selectByCondition3(
@Param("status")Integer status,
@Param("companyName")String companyName,
@Param("brandName")String brandName);
@Test
public void selectByCondition2() throws IOException {
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession sqlSession=sqlSessionFactory.openSession();
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
System.out.println("多条件查询:不为null或空串就查询");
System.out.println(brandMapper.selectByCondition2(0,"%三%",null));
System.out.println("多条件查询:最多只查询一个条件");
System.out.println(brandMapper.selectByCondition3(null,"%三%","%四%"));
sqlSession.close();
}
6.如何实现添加数据?添加数据等需要修改数据库表的内容的操作需要如何提交事务?
<insert id="add">
insert into tb_brand (brand_name, company_name, ordered, description, status)
values (#{brandName},#{companyName},#{ordered},#{description},#{status});
</insert>
void add(Brand brand);
@Test
public void add() throws IOException {
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
System.out.println("6.2在使用openSession时传递参数true设置为默认提交事务");
SqlSession sqlSession=sqlSessionFactory.openSession(true);
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
brandMapper.add(new Brand("京东","京东",10,"京东~",1));
sqlSession.close();
}
7.如何在添加数据之后快速获得该数据自动增长的id?
7.使用userGeneratedKeys与keyProperty属性可在添加数据时, 把数据库中的表中自动增长的数据赋值给实体类对象的属性(自动增长的id)<insert id="add2" useGeneratedKeys="true" keyProperty="id"> insert into tb_brand (brand_name, company_name, ordered, description, status) values (#{brandName},#{companyName},#{ordered},#{description},#{status}); </insert>
void add2(Brand brand);
@Test
public void add2() throws IOException {
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession sqlSession=sqlSessionFactory.openSession(true);
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
Brand brand = new Brand("京东","京东",10,"京东~",1);
brandMapper.add2(brand);
System.out.print("7.添加数据的id为:");
System.out.print(brand.getId());
sqlSession.close();
}
8..如何实现修改数据?修改数据能自动返回什么消息?
<update id="updateById">
update tb_brand set
status =#{status},
company_name =#{companyName},
brand_name =#{brandName},
ordered =#{ordered},
description =#{description}
where id=#{id};
</update>
int updateById(Brand brand);
@Test
public void updateById() throws IOException {
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession sqlSession=sqlSessionFactory.openSession(true);
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
Brand brand = new Brand(6,"淘宝","淘宝",10,"阿里巴巴~",1);
System.out.print("8.修改数据,方法可返回修改条数:");
System.out.println(brandMapper.updateById(brand));
sqlSession.close();
}
9.传递数据为空的话数据也会修改吗?如何实现动态修改数据?
9.动态修改数据 当传输的数据为空时,修改的数据也会变成空 使用set标签(只使用if标签可能会多出逗号)<update id="updateById2"> update tb_brand <set> <if test="brandName!=null and brandName!=''"> brand_name =#{brandName}, </if> <if test="companyName!=null and companyName!=''"> company_name =#{companyName}, </if> <if test="ordered!=null"> ordered =#{ordered}, </if> <if test="status!=null"> status =#{status}, </if> <if test="description!=null and description!=''"> description =#{description} </if> </set> where id=#{id}; </update>
int updateById2(Brand brand);
@Test
public void updateById2() throws IOException {
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession sqlSession=sqlSessionFactory.openSession(true);
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
Brand brand = new Brand(5,"",null,20,"阿里巴巴~",1);
brandMapper.updateById2(brand);
sqlSession.close();
}
修改前:
修改后:
10.根据id实现批量删除数据可向接口中传递数组,如何实现批量删除?
删除单个:
<delete id="deleteById">
delete from tb_brand where id =#{id};
</delete>
int deleteById(int id);
@Test
public void deleteById() throws IOException {
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession sqlSession=sqlSessionFactory.openSession(true);
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
brandMapper.deleteById(5);
sqlSession.close();
}
批量删除:
mybatis会将数组参数封装为map集合 键为array,值是数组 这里使用foreach遍历数组 collection在这里可以写array,也能写arg0 item表示每一个数据,是#{}中的内容 separator分隔符,open 与close表示在这段左边与右边添加()<delete id="deleteByIds"> delete from tb_brand where id in <foreach collection="array" item="id" separator="," open="(" close=")"> #{id} </foreach>; </delete>
int deleteByIds(int[] ids);
@Test
public void deleteByIds() throws IOException {
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession sqlSession=sqlSessionFactory.openSession(true);
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
int[] arr = {1,2,3,4};
brandMapper.deleteByIds(arr);
sqlSession.close();
}
11.mapper接口中传入的参数不同,对应在mapper.xml文件中引用该参数应该如何描述?
pojo类:属性名
map集合:键名
Collection:collection
List:collection/list
数组:array
也可以使用arg0~n来引用