Mybatis
构建mybatis项目的步骤:
1.
使用idea新建一个maven工程
2.
pom.xml文件中中导入相应的依赖,一般基础的依赖包括如下几个
<!--导入mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!--导入mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<!--导入junit依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
mybatis核心配置文件(resources下,springBoot中直接导入依赖坐标即可,配置好数据库连接,不用配置mybatis-config.xml):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是数据库的连接信息-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/db1?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="208713"/>
</dataSource>
</environment>
</environments>
<!--mappers指定sql映射文件的路径-->
<mappers>
<!--加载sql的映射文件-->
<!--<mapper resource="MybatisDemo/Mapper/BrandMapper.xml"/>-->
<!--注释掉上面的一句,改为下面一句,使用包扫描的方式,只要是Mapper文件夹下中的mapper接口,都能扫描出来,但命名规则需要一致-->
<package name="MybatisDemo.Mapper"/>
</mappers>
</configuration>
***还有一个logback,这个根据自己的需要添加:
<!--添加slf4j日志api-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.2</version>
</dependency>
<!--添加logback-classic依赖-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
<!--添加logback-core依赖-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.11</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
logback日志还要在resources中新建一个logback.xml配置文件:
logback.xml
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<!--CONSOLE:表示当前的日志信息是可以输出到控制台的-->
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>[%level] %blue(%d{HH:mm:ss.SSS}) %cyan([%thread]) %boldGreen(%logger{15}) - %msg %n</pattern>
</encoder>
</appender>
<logger>
<appender-ref ref="Console"/>
</logger>
</configuration>
3.
在src/main/java文件夹下建立pojo,mapper等文件夹,当然,也可以先建立一个文件夹,将pojo,mapper等文件夹放到里面,由于resources和java目录都是在main目录下的,maven中默认两者是同一个文件夹,因此,resources中的.xml文件寻找相应的类时,如果这个类是直接在java文件夹下,直接写类名即可,不需要再逐级查找:
例如:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zR8915nT-1649061081643)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20220330091934824.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZyPpUkrU-1649061081644)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20220330091956360.png)]
在maven1的项目中,maven核心配置文件mybatis-config.xml中的标签字段中通过包扫描机制查找mapper接口,直接写成即可,不用写成java.MybatisDemo.Mapper。
注意:采用这种包扫描机制查找mapper接口时,要保证pojo类中的属性和数据库中属性的名称命名方式相同,常见的一个错误就是,数据库中用brand_name命名,而pojo类中的属性用brandName命名,这样会导致mybatis因为查找到的名称不对应,无法完成自动封装(解决方法下面会有详解)。
4.
编写mapper文件夹中各个接口对应的映射文件(xxxMapper.xml)
下面以BrandMapper.xml为例
pojo中实现Brand类:
public class Brand {
private int id;
private String brand_name;//这里采用的命名方式和数据库表中的命名方式相同
private String company_name;
private int orderd;
private String description;
private int status;
...
}
Mapper中的BrandMapper接口
public interface BrandMapper {
/*查询所有*/
List<Brand> selectAll();
Brand selectById(int id);
}
注:在mybatis的映射机制中,sql标签(<select\insert…>)中的resultType对应的实体类的属性名称和数据类型,只有与数据库中的属性名对应上时,才会自动封装,否则不会映射成功,当属性名不一致时,要使用resultmap手动编写代码指明映射。
第一种方式(最初)
BrandMapper.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="test">
<select id="selectAll" resultType="MybatisDemo.pojo.Brand">
select * from tb_brand;
</select>
</mapper>
对于其他sql语句标签,例如,等
<delete id="deleteByUserId" parameterType="java.lang.Integer">
delete from introduction.resumes where user_id = #{user_id};
</delete>
<insert id="addResume" parameterType="com.xdhyy.resume.pojo.Resume">
insert into introduction.resumes(resume_id,resume_name,age,work_experience,education_experience,telephone_number,email_address,intention,detail,user_id)
values(#{resume_id},#{resume_name},#{age},#{work_experience},#{education_experience},#{telephone_number},#{email_address},#{intention},#{detail},#{user_id});
</insert>
MybatisDemo中的测试:
public class MybatisDemo {
public static void main(String[] args) throws Exception{
//1.加载Mybatis的核心配置文件,获取SqlSessionFactory
//String resource = "resources/mybatis-config.xml";
//java文件夹下的类会主动到resources下寻找相应的.xml文件,直接写mybatis-config.xml即可,不必写resources/mybatis-config.xml
String resource="mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象,用来执行sql
SqlSession sqlSession=sqlSessionFactory.openSession();
//执行sql语句
//下面的语句是对应的没有使用包扫描方式的方法,有些语句已经在配置文件中注释掉了
List<User> users=sqlSession.selectList("test.selectAll");
System.out.println(users);
//释放资源
sqlSession.close();
}
}
第二种方式(使用Mapper代理)
在使用Mapper代理时,要注意数据库属性与pojo类种属性命名的方式是否一致,否则Mybatis无法完成自动封装。
Mapper代理中为了保证BrandMapper.xml文件能映射到Mapper中的接口,要在resources中建立一个与xxxMapper接口所在文件夹相同的文件夹,存储xxxMapper.xml文件,这里在resources中新建MybatisDemo.Mapper文件夹时,在新建时,要写成MybatisDemo/Mapper,不要写成Mybatis.Mapper
<?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">
<!--注意!注意!:这里在resources中新建MybatisDemo.Mapper文件夹时,在新建时,要写成MybatisDemo/Mapper,不要写成Mybatis.Mapper-->
<mapper namespace="MybatisDemo.Mapper.BrandMapper">
<!--使用mapper代理时,此时的id='selectAll'表示接口UserMapper中
必有一个名为selectAll的方法,返回值的类型为User(由MybatisDemo.pojo.User得知)
这与不适用mapper代理还是有区别的,不使用mapper代理时,使用sqlSession.selectList("test.selectAll")
test.selectAll由namespace+id组成-->
<select id="selectAll" resultType="MybatisDemo.pojo.Brand">
select * from tb_brand;
</select>
<!--这里的参数parameterType可以省略-->
<select id="selectById" parameterType="int" resultType="MybatisDemo.pojo.Brand">
select * from tb_brand where id=#{id};
</select>
<!--这里是select * ,对实体类中的属性的命名没有要求,当不是select *的时候,才会有要求(数据库中的属性名和实体类中的属性名一致,否则不能自动封装)
例如:
<select id="selectOne" resultType="Mybatisdemo.pojo.Brand">
select brand_name from tb_brand as brandName where id=1;<!--将数据库中的属性名brand_name设为实体类中的对应名brandName-->
</select>
-->
</mapper>
<?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="MybatisDemo.Mapper.BrandMapper">
<select id="selectAll" resultType="MybatisDemo.pojo.Brand">
select * from tb_brand;
</select>
<select id="selectById" parameterType="int" resultType="MybatisDemo.pojo.Brand">
select * from tb_brand where id=#{id};
</select>
</mapper>
MybatisDemo中测试:
public class MybatisDemo2 {
public static void main(String[] args) throws Exception{
//mybatis的mapper代理模式
//1.加载mybatis的核心配置文案,获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象,用于执行sql
SqlSession sqlSession=sqlSessionFactory.openSession();
//3.1获得UserMapper接口的代理对象,这个过程是由mybatis内部实现的
/*这种方式的好处是,当Mapper文件夹中有多个mapper接口时,并且mapper接口中有多个方法时
* 比不适用mapper代理要轻松的多*/
//从下面这一句开始,与MybatisDemo中的代码有所不同。
//使用SqlSession中的getMapper(UserMapper.class)获得接口的代理对象
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
BrandMapper brandMapper=sqlSession.getMapper(BrandMapper.class);
List<User> users=userMapper.selectAll();//这个selectAll()返回的类型是User类型
List<Brand> brands=brandMapper.selectAll();
System.out.println(users);
System.out.println(brands);
sqlSession.close();
}
}
使用Mapper代理后,还可以对XXXMapper.xml进行改进:
改进一:
使用sql语句将可以重复使用的语句封装起来:
<?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="MybatisDemo.Mapper.BrandMapper">
<!--可已将sql语句的公共部分提取出来,如下,将brand_name as brandName提取出来-->
<sql id="brand_column">brand_name as brandName</sql>
<!--这个时候的select标签中的依旧是属性resultType,在使用resultMap时要改为resultMap-->
<select id="selectOne" resultType="Mybatisdemo.pojo.Brand">
select
<include refid="brand_column"/>
from tb_brand;
</select>
</mapper>
改进二 resultmap(至于是否使用到这种改进,要看数据库中的属性名和自己写的dao层的实体类的属性名是否相同,如果相同,则不用使用resultmap):
使用restltmap,以后会经常用到:
<?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">
<!--注意!注意!:这里在resources中新建MybatisDemo.Mapper文件夹时,在新建时,要写成MybatisDemo/Mapper,不要写成Mybatis.Mapper-->
<mapper namespace="MybatisDemo.Mapper.BrandMapper">
<resultMap id="brandResultMap" type="Brand">
<!--
id:完成主键字段的映射
column:表的列名
property:实体类的属性名
result:完成一般字段的映射
column:表的别名
property:实体类的属性名
-->
<!--将数据库中的属性brand_name转为实体类中的brandName,这样对应上了就能进行自动封装了-->
<result column="brand_name" property="brandName"/>
<result column="company_name" property="companyName"/>
</resultMap>
<!--调用resultMap之后,select标签中的属性resultType改为resultMap-->
<select id="selectAll" resultMap="brandResultMap">
select * from tb_brand;
</select>
</mapper>
处理对于含有参数的查找时,XXXMapper.xml文件的配置:
BrandMapper接口:
public interface BrandMapper {
Brand selectById(int id);
List<Brand> selectAll();
}
BrandMapper.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="Mapper.BrandMapper">
<resultMap id="brandResultMap" type="pojo.Brand">
<result column="brand_name" property="brandName"/>
<result column="company_name" property="companyName"/>
</resultMap>
<!--调用resultMap之后,select标签中的属性resultType改为resultMap-->
<select id="selectAll" resultMap="brandResultMap">
select * from tb_brand;
</select>
<!--下面的参数parameterType也可以不写-->
<select id="selectById" parameterType="int" resultMap="brandResultMap">
select * from tb_brand where id=#{id};
<!--保持#{?}中?号处的参数和mapper接口中的参数一致即可-->
</select>
</mapper>
<!--
1.#{}:会将其替代为?,可以防止sql注入(类似于JDBC中的PrepareStatement)
2.${}:拼接sql,会存在SQL注入问题b
3.使用时机:
参数传递的时候:#{}
表名或者列名不固定的情况下:${}
4.参数类型:parameterType:这个可以省略
5.特殊字符的解决:
<,>等符号在xml中要用特殊的字符代替
1.转义字符
2.CDATA区
CDATA区的使用:
<select id="selectById" resultMap="brandResultMap">
select * from tb_brand where <![CDATA[<]]>#{id};
</select>
-->
查询:查询所有数据和按照某个属性查询上面已经讲过,下面是条件查询。
条件查询:
1.多条件查询
参数接收有下面三种方式:
1.散装参数,使用@Param注解
List<Brand> selectByCondition(@Param("status")int status,@Param("companyName")String companyName,@Param("brandName")String brandName);
//@Param的作用就是告诉Mybatis将参数status传给.xml文件中的status,双引号中的是.xml文件中的参数。
2.对象参数:对象属性的名称要和参数占位符的名称一致
List<Brand> selectByCondition(Brand brand);
3.map集合参数
List<Brand> selectByCondition(Map map);
上面对应的java语句中的参数要传到下面的对应的值中。
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
where
status=#{status}
and company_name like#{companyName}
<!--模糊查询时,java程序中的参数要在前后加上%,否则会查询错误 -->
and brand_name like#{brandName}
</select>
int status=1;
String companyName="%华为%";
String brandName="%华%";
/*BrandMapper接口中的代码
List<Brand> selectByCondition(@Param("status") int status,@Param("companyName") String companyName, @Param("brandName") String brandName);
List<Brand> selectByCondition(Brand brand);
List<Brand> selectByCondition(Map map);*/
//使用散装参数查询
List<Brand> brands1=brandMapper.selectByCondition(status,companyName,brandName);
//使用对象参数
Brand brand_test=new Brand();
List<Brand> brands1=brandMapper.selectByCondition(brand_test);
//使用map集合
Map map_test=new HashMap();
map_test.put("status",status);
map_test.put("companyName",companyName);
map_test.put("brandName",brandName);
List<Brand> brands1=brandMapper.selectByCondition(map_test);
//上述三种方式的结果都是一样的
动态SQL查询:
动态SQL语句就是加入一些条件判断语句,处理参数为空的特殊情况
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
<!--1=1是为了缓冲and,或者直接使用<where></where>标签-->
<!--where 1=1-->
<where>
<if test="status !=null">
and status=#{status}
</if>
<if test="companyName !=null and companyName!=''">
and company_name like#{companyName}
</if>
<!--模糊查询时,java程序中的参数要在前后加上%,否则会查询错误 -->
<if test="brandName !=null and brandName!=''">
and brand_name like#{brandName}
</if>
</where>
</select>
<!--
mybatis中的动态sql
if
choose(when,otherwise)
trim(where,set)
foreach
-->
单条件的动态查询:
<select id="selectByConditionSingle" resultMap="brandResultMap">
select *
from tb_brand
where
<choose><!--类似于switch-->
<when test="status!=null"><!--类似于case-->
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>
<otherwise><!--类似于d-->
1=1
</otherwise>
</choose>
</select>
内容来自于该教程的总结:
https://www.bilibili.com/video/BV1Qf4y1T7Hx?p=56