1、基本配置
思路:搭建环境—>导入mybatis—>编写代码—>测试
1、创建项目并删除src把项目当做父工程
2、导入依赖
<dependencies>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!-- 单元测试依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
3、配置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核心配置文件-->
<configuration>
<!--environments:环境,可配置多个环境;default="development":默认使用id="development"这个环境-->
<environments default="development">
<environment id="development">
<!--transactionManager:事务管理方式,使用JDBC的事务管理-->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=true&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="admin"/>
<property name="password" value="admin"/>
</dataSource>
</environment>
</environments>
</configuration>
2、编写mybatis工具类
在Utils包下创建MybatisUtils工具类,用来获取SqlSession
package com.abner.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;
//SqlSessionFactory --> SqlSession
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
//使用mybatis第一步:获取SqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
// SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
public static SqlSession getSqlSession(){
SqlSession sqlSession = sqlSessionFactory.openSession();
return sqlSession;
}
}
4、编写代码
- 实体类
package com.abner.pojo;
//实体类
public class User {
private int id;
private String name;
private int age;
private String sex;
public User() {
}
public User(int id, String name, int age, String sex) {
this.id = id;
this.name = name;
this.age = age;
this.sex = sex;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
- Dao接口类
package com.abner.dao;
import com.abner.pojo.User;
import java.util.List;
public interface UserDao {
List<User> getUserList();
}
- 接口实现类由原来的UserDaoImpl转变为UserMapper.xml配置文件(放在dao包下,其他地方也可以)
<?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绑定一个对应的Dao(Mapper)接口-->
<mapper namespace="com.abner.dao.UserDao">
<select id="getUserList" resultType="com.abner.pojo.User">
select * from user;
</select>
</mapper>
我们的Dao类想要执行UserMapper.xml里面的SQL,必须用namespace来唯一定位,即把dao和配置文件绑定起来,其原理和我们之前用impl类实现对应接口的原理是一样的。
select标签中 id对应的是Dao(Mappetr)类中的方法名字(必须一样),和之前实现接口重写其方法是一样的。
resultType为返回的数据类型(Dao类中返回值类型或返回值类型中的泛型的类型),和我们之前在实现类中执行完SQl获取的的结果集返回一样
5、测试
Junit测试
package com.abner.dao;
import com.abner.pojo.User;
import com.abner.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class UserDaoTest {
@Test
public void test(){
//1、获得SqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//2、方式一:执行sql
UserDao mapper = sqlSession.getMapper(UserDao.class);
List<User> userList = mapper.getUserList();
for (User user : userList) {
System.out.println(user.toString());
}
//关闭session
sqlSession.close();
}
}
测试成功
注意点:
这里的错误是指在Mapper在Mapper注册中心里面类型接口Dao是未知的
MapperRegistry(Mapper注册中心)是什么?
<!--每一个Mapper.xml都需要在MyBatis配置文件中注册-->
<mappers>
<mapper resource="com/abner/dao/UserMapper.xml"/>
</mappers>
resource绑定mapper,需要使用路径,不能用com.xx.xx这种方式
还有其他方式的绑定
错误二,初始化错误,原因的找不到Mapper.xml,但是我们不是已经在核心配置文件中注册了吗?
我们把UserMapper.xml问价复制到生成的target目录下的dao包下发现可以执行成功。那不可能每次都复制过去吧?
解决办法是在pom.xml文件中添加一下内容
<!--在build中配置resource,来防止我们的资源导出失败问题-->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
false老师那里是true,但是我这里是true还是报错,改成false就成功了
错误三:https://blog.csdn.net/L_it123/article/details/106845391
最基础的构建顺序
2、实现增删改查(CRUD)
namespace:要和Dao(Mapper)接口的报名一样
1、select
<select id="getUserList" resultType="com.abner.pojo.User" parameterType="xxx">
select xxx from user where xxx=#(xxx);
</select>
选择,查询语句:
- id:就是对应的namespace中的方法名
- resultType:Sql语句执行的返回值
- parameterType:Dao(Mapper)方法的参数类型
根据id查询用户
1、编写接口
//根据id查询用户
User getUserById(int id);
2、编写对应的mapper.xml中的sql语句
<select id="getUserById" resultType="com.abner.pojo.User" parameterType="int">
select * from user where id=#{id};
</select>
#{id}为接收方法的参数,里面的名应该和参数名一样
2、insert
1、编写接口
//insert一个用户
int insertUser(User user);
2、编写对应的mapper.xml中的sql语句
<!--对象中的属性,可以直接取出来-->
<insert id="insertUser" parameterType="com.abner.pojo.User">
insert into user(id, name, age, sex) values (#{id} ,#{name},#{age},#{sex});
</insert>
我们方法的参数是User类型,在sql中只要接收的参数名和user的属性名一致,就可以接收到user里面对应属性的值。
3、update
1、编写接口
//修改用户
int updateUser(User user);
2、编写对应的mapper.xml中的sql语句
<update id="updateUser" parameterType="com.abner.pojo.User">
update user set name=#{name},age=#{age},sex=#{sex} where id=#{id};
</update>
我们方法的参数是User类型,在sql中只要接收的参数名和user的属性名一致,就可以接收到user里面对应属性的值。
4、delete
1、编写接口
//删除用户
int deleteUser(int id);
2、编写对应的mapper.xml中的sql语句
<delete id="deleteUser" parameterType="int">
delete from user where id=#{id};
</delete>
注意我们在增、删、改的时候需要提交事务(sqlSession.commit()
)
测试类:
package com.abner.dao;
import com.abner.pojo.User;
import com.abner.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class UserDaoTest {
@Test
public void test(){
//1、获得SqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
try {
// //2、方式一:执行sql
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserList();
//方式二:
//List<User> userList = sqlSession.selectList("com.abner.dao.UserDao.getUserList");
for (User user : userList) {
System.out.println(user.toString());
}
}catch (Exception e){
e.printStackTrace();
}finally {
//关闭session
sqlSession.close();
}
}
@Test
public void getUserById(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.getUserById(5);
System.out.println(user);
sqlSession.close();
}
//增删改需要提交事务sqlSession.commit();
@Test
public void insertUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = new User(8,"小巴",25,"女");
int res = mapper.insertUser(user);
if(res>0){
System.out.println("插入成功!");
}
//提交事务
sqlSession.commit();
sqlSession.close();
}
@Test
public void updateUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = new User(9,"王九",30,"男");
int res = mapper.updateUser(user);
if(res>0){
System.out.println("更新成功!");
}
sqlSession.commit();
sqlSession.close();
}
@Test
public void deleteUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int res = mapper.deleteUser(10);
if(res>0){
System.out.println("删除成功!");
}
sqlSession.commit();
sqlSession.close();
}
}
3、万能的Map
//insert一个用户
int insertUser2(Map<String,Object> map);
<insert id="insertUser2" parameterType="map">
insert into user(id, name, age, sex) values (#{id} ,#{name},#{age},#{sex});
</insert>
//增删改需要提交事务sqlSession.commit();
@Test
public void insertUser2() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String,Object> map = new HashMap<String, Object>();
map.put("id",10);
map.put("name","小狗");
map.put("age",14);
map.put("sex","雄");
int res = mapper.insertUser2(map);
if (res > 0) {
System.out.println("插入成功!");
}
//提交事务
sqlSession.commit();
sqlSession.close();
}
只要map中的key的值和sql中的获取参数的名字一样,就可以获取到map中对应key的value,所以我们想传什么字段就在map中put进去一个字段,而不用反复的修改实体类,所以说这是万能的map,很灵活。
Map传递参数,直接在sql中取出key即可!
对象传递参数,直接在sql中取出对象的属性即可!
只有一个基本类型的参数情况下,可以直接在Sql中取到
4、配置解析
1、核心配置文件
mybatis-config.xml(官方推荐名)
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
- environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
- environment(环境变量)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
2、引入外部配置文件(properties文件)
db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=utf8
username=admin
password=admin
在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>
<!--引入properties文件用<properties>标签,
标签之间有顺序
properties->settings->typeAliases->typeHandlers->objectFactory->objectWrapperFactory->reflectorFactory->
plugins->environments->databaseIdProvider->mappers
-->
<!--引入外部配置文件-->
<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>
<mappers>
<mapper resource="com/abner/mybatis/dao/UserMap
per.xml"/>
</mappers>
</configuration>
引入之后就可以用${属性}获取properties文件对应属性的值
在properties标签中可以直接增加属性
<properties resource="db.properties">
<property name="username" value="admin"/>
<property name="passwordd" value="admin"/>
</properties>
如果properties标签中的property的属性名和外部配置文件中的属性名相同,会优先使用外部配置文件的;
3、类型别名(typeAliases)
在核心配置文件中指定某个类的别名
<!--给实体类型起别名-->
<!--方式一-->
<typeAliases>
<typeAlias type="com.abner.mybatis.pojo.User" alias="User"/>
</typeAliases>
<!--方式二,扫描实体类所在的包,会使用实体类类名的首字母小写来作为它的别名(大写也行)-->
<typeAliases>
<package name="com.abner.mybatis.pojo"/>
</typeAliases>
那么我们在mapper.xml文件中使用别名
<select id="getUserList" resultType="User">
select * from user;
</select>
在实体类比较少的时候,推荐使用第一种
如果实体类比较多,建议第二种
第一种可以DIY,第二种则不行,如果非要改,需要在实体类上添加注解@Alias(“别名”)
4、设置(setting)
设置(settings)相关 => 查看帮助文档
-
懒加载
-
日志实现
-
缓存开启关闭
一个配置完整的 settings 元素的示例如下:
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>
5、映射器mapper
MapperRegistry:注册绑定我们的Mapper文件:
方式一:使用mapper.xml注册绑定(推荐使用)
<!--每一个Mapper.xml都需要在MyBatis配置文件中注册-->
<mappers>
<mapper resource="com/abner/mybatis/dao/UserMapper.xml"/>
</mappers>
方式二:使用class文件绑定注册
<!--
使用映射器接口实现类的完全限定类名
需要配置文件名称和接口名称一致,并且位于同一目录下
-->
<mappers>
<mapper class="com.abner.mybatis.dao.UserMapper"/>
</mappers>
使用方式二的注意点:
- 接口和他的Mapper.xml配置文件必须同名
- 接口和他的Mapper.xml配置文件必须在同一个包下
方式三:使用扫描包注入绑定
<!--
将包内的映射器接口实现全部注册为映射器
但是需要配置文件名称和接口名称一致,并且位于同一目录下
-->
<mappers>
<package name="com.abner.mybatis.dao"/>
</mappers>
注意点和方式二一样
6、结果集映射
如果我们实体类的属性名和数据库表中的字段名不一致的话,那么查询出来的结果会映射不到实体类上
那么我们就需要在mapper.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="com.abner.mybatis.dao.UserMappers">
<!--结果集映射-->
<resultMap id="UserMap" type="User">
<!--column数据库中的字段名,property实体类中的属性名-->
<result column="id" property="id"/>
<result column="name" property="name" />
<result column="age" property="age"/>
<result column="sex" property="sexx"/>
</resultMap>
<select id="getUserById" resultMap="UserMap">
select * from user where id=#{id};
</select>
</mapper>
5、使用注解开发
在mybatis-config.xml文件中用接口注册mapper
<mappers>
<mapper class="com.abner.mybatis.dao.UserMapper"/>
</mappers>
然后在接口的方法中使用@Select、@Insert、@Update、@Delete标签
package com.abner.mybatis.dao;
import com.abner.mybatis.pojo.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
public interface UserMapper {
@Select("select * from user")
List<User> getUsers();
@Select("select * from user where id = #{id}")
User getUserById(@Param("id") int id);
@Insert("insert into user(name,age,sex) values(#{name},#{age},#{sex}) ")
int addUser(User user);
@Update("update user set name = #{name},age=#{age},sex=#{sex} where id = #{id}")
int updateUser(User user);
@Delete("delete from user where id = #{id}")
int deleteUserById(@Param("id") int id);
}
有参数的方法用@Paramb绑定参数,sql语句中获取的id就是@Param中的值绑定的,即#{}里面的id对应@Param()的id
注意:
- 一定要把接口注册绑定到我们的核心配置文件中
6、 动态SQL
1、if
如果某个条件是第一个条件并且前面有and,where标签会把第一个条件的and去掉。
<!--动态Sql-->
<select id="queryBlogIF" parameterType="map" resultType="Blog">
select * from blog
-- 如果下面有如何条件的会自动增加where子句
<where>
-- 如果有传入title这个参数,就会怎sql后面拼接if里面语句
<if test="title != null">
title = #{title}
</if>
-- 如果有传入author这个参数,就会怎sql后面拼接if里面语句,如果没有传上面的title,会自动把and去掉
<if test="author != null">
and author = #{author}
</if>
</where>
</select>
2、 choose
有时候,我们不想用到所有的查询条件,只想选择其中的一个,查询条件有一个满足即可,使用 choose 标签可以解决此类问题,类似于 Java 的 switch 语句
<select id="queryBlogChoose" parameterType="map" resultType="Blog">
select * from blog
<where>
-- 相当于switch case 语句,只要从上往下检查,只要碰到满足的条件的就结束,不在拼接后面的,如果都不满足,就拼接otherwise中的
<choose>
<when test="title != null">
title = #{title}
</when>
<when test="author != null">
and author = #{author}
</when>
<otherwise>
and views = #{views}
</otherwise>
</choose>
</where>
</select>
3、set
同理,上面的对于查询 SQL 语句包含 where 关键字,如果在进行更新操作的时候,含有 set 关键词,我们怎么处理呢?
<update id="updateBlob" parameterType="map">
update blog
-- set元素会动态前置SET关键字,同时也会删除无关的逗号
<set>
<if test="title != null">
title = #{title},
</if>
<if test="author != null">
author = #{author}
</if>
</set>
where id = #{id}
</update>
所谓的动态SQL本质还是SQL语句,知识我们可以在SQL层面,去执行一个逻辑代码
4、foreach
将数据库中前三个数据的id修改为1,2,3;
需求:我们需要查询 blog 表中 id 分别为1,2,3的博客信息
1、编写接口
List<Blog> queryBlogForeach(Map map);
2、编写SQL语句
<select id="queryBlogForeach" parameterType="map" resultType="blog">
select * from blog
<where>
<!--
collection:指定输入对象中的集合属性
item:每次遍历生成的对象
open:开始遍历时的拼接字符串
close:结束时拼接的字符串
separator:遍历对象之间需要拼接的字符串
select * from blog where 1=1 and (id=1 or id=2 or id=3)
-->
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id=#{id}
</foreach>
</where>
</select>
3、测试
@Test
public void testQueryBlogForeach(){
SqlSession session = MybatisUtils.getSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
HashMap map = new HashMap();
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(2);
ids.add(3);
map.put("ids",ids);
List<Blog> blogs = mapper.queryBlogForeach(map);
System.out.println(blogs);
session.close();
}
5、抽取SQL片段
有时候我们可能会将一些功能的部分抽取出来,方便复用
1、使用SQL标签抽取公共的部分
<!--把公共的动态SQL片段提取出来,在需要用到的地方用include标签引用-->
<sql id="if-title-author">
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</sql>
2、在需要使用的地方使用include标签引用即可
<!--动态Sql-->
<select id="queryBlogIF" parameterType="map" resultType="Blog">
select * from blog
<where>
<include refid="if-title-author"></include>
</where>
</select>
注意事项:
- 最好基于单表来定义SQL片段
- 不要存在where标签