一、概念
1.1、概念
依赖网站:https://mvnrepository.com/
二、步骤
1、Maven项目配置MyBatis
<dependencies>
<!--MyBatis核心依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
</dependencies>
<?xml version="1.0" encoding="UTF-8"?>
<!--mybatis配置文件头,特点为首尾的“configuration”和“mybatis-3-config.dtd”-->
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--核心配置信息-->
<environments default="shine_config">
<!--数据库相关配置-->
<environment id="shine_config">
<!--事务控制类型-->
<transactionManager type="JDBC"></transactionManager>
<!--数据库连接参数-->
<dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory">
<property name="driver" value="com.mysql.cj.jdbc.Driver"></property>
<!--&转义&-->
<property name="url" value="jdbc:mysql://localhost:3306/mybatis_shine?serverTimezone=UTC&useUnicode=true&useSSL=false&characterEncoding=UTF-8"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</dataSource>
</environment>
</environments>
</configuration>
2、开发步骤
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String username;
private String password;
private Boolean gender;
private Date regist_time;
}
public interface UserDao {
User queryUserById(Integer id);
}
<?xml version="1.0" encoding="UTF-8"?>
<!--mybatismapper文件头,特点为首尾的“mapper”和“mybatis-3-mapper.dtd”-->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao.UserDao">
<!--描述方法-->
<!--id为方法名,resultType为返回值类型,arg0表示参数的第一个值-->
<!--queryUserById是Dao中的方法名-->
<select id="queryUserById" resultType="entity.User">
select id,username,password,gender,regist_time
from t_user
where id=#{arg0}
</select>
</mapper>
<!--注册mapper文件-->
<mappers>
<mapper resource="UserDaoMapper.xml"/>
</mappers>
public class TestMybatis {
public static void main(String[] args) throws IOException {
//mybatis API
//1.加载配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//2.构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.通过sqlSessionFactory创建sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//4.通过sqlSession获得DAO实现类的对象
UserDao mapper = sqlSession.getMapper(UserDao.class);
//5.测试查询方法
User user1 = mapper.queryUserById(1);
User user2 = mapper.queryUserById(2);
System.out.println(user1);
System.out.println(user2);
sqlSession.close()
}
}
2.1一些问题
<!--========在pom.xml文件中更改默认编译规则==========================================================-->
<build>
<!--更改Maven编译规则-->
<resources>
<resource>
<!--资源目录-->
<directory>src/main/java</directory>
<!--扫描资源目录下的所有xml文件-->
<includes>
<include>*.xml</include> <!--默认(新添加自定义则失效)-->
<include>**/*.xml</include><!--新添加 */代表1级目录 **/代表多级目录-->
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
<!--========mybatis配置文件中注册mapper文件的路径====================================================-->
<mappers>
<mapper resource="dao/UserDaoMapper.xml"/>
</mappers>
<!--
1.在resource目录下创建jdbc-properties文件,并将mybatis配置文件中的url,driver,username,password内容复制到文件相应位置中
-->
jdbc.url = jdbc:mysql://localhost:3306/mybatis_shine?serverTimezone=UTC&useUnicode=true&useSSL=false&characterEncoding=UTF-8
jdbc.driver = com.mysql.cj.jdbc.Driver
jdbc.username = root
jdbc.password = 123456
<!--
2.在mybatis配置文件中导入jdbc-properties文件
-->
<properties resource="jdbc-properties"></properties>
<!--
3.将mybatis配置文件的数据库连接参数更改为动态参数
-->
<dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory">
<property name="driver" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</dataSource>
<!--往后更改数据库连接信息只需在jdbc-properties文件中修改即可-->
<!--
方法1,设置某个类的别名,mapper文件中要以这个类为返回对象时,可直接使用设置的别名
-->
<!--在mybatis配置文件中设置实体类别名映射-->
<typeAliases>
<typeAlias type="entity.User" alias="user_shine"/>
</typeAliases>
<!--在对应mapper文件中使用别名-->
<select id="queryUserById" resultType="user_shine">
select id,username,password,gender,regist_time
from t_user
where id=#{arg0}
</select>
<!--
方法2,定义实体类所在的包,每个实体类自动注册一个别名(也就是类名);
mapper文件中要以这个类为返回对象时,可直接写类名
-->
<!--在mybatis配置文件中设置实体类别名映射-->
<typeAliases>
<package name="entity"/>
</typeAliases>
<!--在对应mapper文件中使用别名-->
<select id="queryUserById" resultType="User">
select id,username,password,gender,regist_time
from t_user
where id=#{arg0}
</select
# 在resource目录下创建log4j.properties文件(固定名字)
# 运行项目就会输出日志
log4j.rootLogger=DEBUG, stdout
log4j.logger.org.mybatis.example.BlogMapper=TRACE
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
三、CURD操作
3.1 查询操作参数绑定的几种方式
<!--dao接口-->
User queryUserByIdAndUsername(Integer id,String username);
<!--mapper文件-->
<select id="queryUserById" resultType="User">
select id,username,password,gender,regist_time
from t_user
<!--arg0和agr1和param2表示数据的第一个值和第二个值-->
where id=#{arg0} and username=#{agr1}
</select>
<!--dao接口-->
User queryUserByIdAndUsername(Integer id,String username);
<!--mapper文件-->
<select id="queryUserById" resultType="User">
select id,username,password,gender,regist_time
from t_user
<!--param1和param2表示数据的第一个值和第二个值-->
where id=#{param1} and username=#{param2}
</select>
<!--dao接口-->
User queryUserByIdAndPassword(@Param("id") Integer id,@Param("password") String password);
<!--mapper文件-->
<select id="queryUserById" resultType="User">
select id,username,password,gender,regist_time
from t_user
<!--此处的id和password是@Param注解定义的名字-->
where id=#{id} and username=#{password}
</select>
<!--dao接口-->
User queryUserByIdAndPassword2(Map map);
<!--mapper文件-->
<select id="queryUserById" resultType="User">
select id,username,password,gender,regist_time
from t_user
<!--此处的id和password是Map的key-->
where id=#{id} and username=#{password}
</select>
<!--测试操作-->
Map map = New HashMap();
map.put("id",2);
map.put("password","456");
<!--dao接口-->
User queryUserByIdAndPassword3(User user);
<!--mapper文件-->
<select id="queryUserById" resultType="User">
select id,username,password,gender,regist_time
from t_user
<!--此处的id和password是User类中定义的属性名-->
where id=#{id} and username=#{password}
</select>
<!--测试操作-->
User user = new User();
user.setId(1);
user.setPassword("123")
3.2 模糊查询
<!--dao接口-->
List<User> queryUserByUsername(@Param("username") String username);
<!--mapper文件-->
<select id="queryUserById" resultType="User">
select id,username,password,gender,regist_time
from t_user
<!--concat做字符串拼接-->
where username like concat('%',#{username},'%')
</select>
3.3 delete操作
<!--dao接口-->
void deleteUser(@Param("id") Integer id);
<!--mapper文件-->
<delete id="deleteUser" parameterType="int">
delete form t_user
where id = #{id}
</delete>
<!--
完成操作后,需要调用commit()方法,将操作持久化到数据库,sqlSession.close()释放资源
-->
3.4 update操作
<!--dao接口-->
void updateUser(User user);
<!--mapper文件-->
<update id="updateUser" parameterType="User">
update t_user
set username=#{username},password=#{password},gender={gender},regist_time=#{regist_time}
where id=#{id}
</update>
<!--
完成操作后,需要调用commit()方法,将操作持久化到数据库,sqlSession.close()释放资源
-->
3.5 insert操作
<!--dao接口-->
void insertUser(User user);
<!--mapper文件-->
<insert id="insertUser" parameterType="User">
insert into t_user values(#{id},#{username},#{password},#{gender},#{regist_time})
</insert>
<!--
完成操作后,需要调用commit()方法,将操作持久化到数据库,sqlSession.close()释放资源
-->
3.6 主键回填
<!--dao接口-->
void insertUser(User user);
<!--mapper文件-->
<insert id="insertUser" parameterType="User">
<!--主键回填,将新数据的ID存入java对象的主键对应的属性中-->
<!--order指定执行顺序,这里的id指的是插入操作中的id参数-->
<selectKey order="AFTER" resultType="int" keyProperty="id">
select last_insert_id()
</selectKey>
insert into t_user values(#{id},#{username},#{password},#{gender},#{regist_time})
</insert>
<!--测试操作-->
User new_ser = new User(null, "shine_652", "00000", true, new Date());
mapper.insertUser(new_ser);
System.out.println(new_ser);<!--查看回填的id-->
sqlSession.commit();
sqlSession.close()
<!--dao接口-->
Integer insertStudent(Student student);
<!--mapper文件-->
<insert id="insertStudent" parameterType="Student">
<!--将主键设置为32位,mysql生成唯一的32位UUID,回填到参数id中-->
<!--使用mysql的replace方法去除生成UUID的短很细和空格-->
<selectKey order="BEFORE" resultType="String" keyProperty="id">
select replace(uuid(),'-','');
</selectKey>
insert into t_student values (#{id},#{name},#{gender});
</insert>
<!--测试操作-->
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
Student student = new Student(null, "shine001", true);
mapper.insertStudent(student);
System.out.println(student);
sqlSession.commit();
sqlSession.close()
四、MyBatis工具类
4.1 封装工具类
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;
/**
* 1.加载配置
* 2.创建SqlSessionFactory
* 3.创建Session
* 4.事务管理
* 5.mapper获取
*/
public class MyBatisUtil {
private static SqlSessionFactory sqlSessionFactory;
//创建ThreadLocal绑定当前线程中的SqlSession对象
private static final ThreadLocal<SqlSession> tl = new ThreadLocal<SqlSession>();
static { //加载配置信息
//1.加载配置文件
try{
//1.加载配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//2.构建SqlSessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}catch (IOException e){
e.printStackTrace();
}
}
//创建sqlSession
public static SqlSession openSession(){
SqlSession sqlSession = tl.get();
if (sqlSession == null) {
sqlSession = sqlSessionFactory.openSession();
tl.set(sqlSession);
}
return sqlSession;
}
//释放资源
public static void closeSession(){
SqlSession sqlSession = tl.get();
sqlSession.close();
}
//提交事务
public static void commit(){
SqlSession sqlSession = openSession();
sqlSession.commit();
closeSession();
}
//事务回滚
public static void rollback(){
SqlSession sqlSession = openSession();
sqlSession.rollback();
closeSession();
}
//mapper获取
public static <T> T getMapper(Class<T> mapper){
SqlSession sqlSession = openSession();
return sqlSession.getMapper(mapper);
}
}
4.2 测试工具类
StudentDao studentMapper = MyBatisUtil.getMapper(StudentDao.class);
Student student = new Student(null, "test_util", true);
studentMapper.insertStudent(student);
MyBatisUtil.commit();
五、映射
5.1 resultMap结果地图
<!--定义复杂情况的,映射规则-->
<resultMap id="user_resultMap" type="User">
<!--主键列,column表示数据表的列名,property表示实体类的属性名-->
<id column="id" property="id"/>
<!--普通列,column表示数据表的列名,property表示实体类的属性名-->
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="gender" property="gender"/>
<!--表列名为registTime,因为是在SQL语句中定义的别名-->
<result column="registTime" property="regist_time"/>
</resultMap>
<select id="queryUserById" resultMap="user_resultMap">
select id,username,password,gender,regist_time registTime
from t_user
where id=#{arg0}
</select>
六、关联查询
6.1 一对一

<mapper namespace="dao.PassengerDao">
<resultMap id="passenger_passport" type="Passenger">
<id column="id" property="id"></id>
<result column="name" property="name"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<!--passport指的是Passenger实体类中的Passport对象属性名-->
<association property="passport" javaType="entity.Passport">
<!--此处的表列名为passId,是在SQL语句中取的别名-->
<id column="passId" property="id"></id>
<result column="nationality" property="nationality"/>
<result column="expire" property="expire"/>
</association>
</resultMap>
<!--查询旅客和护照信息-->
<select id="queryPassengerById" resultMap="passenger_passport">
select t_passengers.id,t_passengers.name,t_passengers.sex,t_passengers.birthday,
t_passports.id passId,t_passports.nationality,t_passports.expire
from t_passengers join t_passports
on t_passengers.id = t_passports.passengers_id
where t_passengers.id = #{id}
</select>
</mapper>
6.2 一对多

<mapper namespace="dao.DepartmentDao">
<resultMap id="department_result" type="Department">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<result column="location" property="location"></result>
<!--employee是主表实体类中的对象属性名-->
<collection property="employee" ofType="Employee" >
<!--列名为SQL别名-->
<id column="emp_id" property="id"></id>
<result column="emp_name" property="name"></result>
<result column="salary" property="salary"></result>
</collection>
</resultMap>
<select id="queryDepartmentById" resultMap="department_result">
select t_departments.id,t_departments.name,t_departments.location,
t_employees.id emp_id,t_employees.name emp_name,t_employees.salary
from t_departments join t_employees
on t_departments.id = t_employees.dept_id
where t_departments.id=#{id}
</select>
</mapper>
6.3 多对多

<!--课程关联学生查询-->
<mapper namespace="dao.SubjectDao">
<resultMap id="subject_result" type="Subject">
<id column="id" property="id"></id>
<result column="name" property="name"/>
<result column="grade" property="grade"/>
<!--student是定义在Subject实体类中的对象属性,Student2是对象属性对应的实体类对象-->
<collection property="students" ofType="Student2">
<id column="stu_id" property="id"></id>
<result column="stu_name" property="name"/>
<result column="sex" property="sex"/>
</collection>
</resultMap>
<select id="querySubjectById" resultMap="subject_result">
select t_subjects.id,t_subjects.name,t_subjects.grade,
t_students.id stu_id,t_students.name stu_name,t_students.sex
from t_subjects join t_stu_sub
on t_subjects.id = t_stu_sub.subject_id
join t_students
on t_stu_sub.student_id = t_students.id
where t_subjects.id = #{id}
</select>
</mapper>
七、动态SQL
7.1 SQL片段抽取
<sql id="user_field">
select id,username,password,gender,regist_time registTime
from t_user
</sql>
<select id="queryUserById" resultType="User">
<include refid="user_field"/>
where id=#{id}
</select>
7.2 if标签
// 假设User实体类中有id和username两个字段
User queryUser(User user)
<!--假设查询User两个字段的任意一个时,判断其不为空(另一个肯定为空),传入其中一个字段值查询-->
<select id="queryUser" resultType="User">
<include refid="user_field"/>
where
<if test="id!=null">
id=#{id}
</if>
<if test="username!=null">
username=#{username}
</if>
</select>
7.3 where标签
// 假设User实体类中有username和gender两个字段
User queryUser(User user)
<!--加上一个or,表示当传入两个值时,两个值都将被带入查询-->
<!--where标签可以去除当传入一个值时可能存在的or或and开头的关键字,避免带入SQL语句查询-->
<select id="queryUser" resultType="User">
<include refid="user_field"/>
<where>
<if test="username!=null">
username=#{username}
</if>
<if test="gender!=null">
or gender=#{gender}
</if>
</where>
</select>
7.4 set标签
User updateUser(User user)
<!--set标签可以去除字段后的逗号-->
<update id="updateUser" parameterType="User">
update t_user
<set>
<if test="username!=null">
username=#{username},
</if>
<if test="password!=null">
password=#{password},
</if>
<if test="gender!=null">
gender=#{gender},
</if>
<if test="registTime!=null">
registTime=#{registTime}
</if>
</set>
where id = #{id}
</update>
7.5 trim标签
<select id="queryUser" resultType="User">
<include refid="user_field"/>
<!--此处trim标签的作用和where一样,去除or或者and开头的关键字-->
<trim prefix="where" prefixOverrides="or|and">
<if test="username!=null">
username=#{username}
</if>
<if test="gender!=null">
or gender=#{gender}
</if>
</trim>
</select>
<!--==============================================================================================-->
<update id="updateUser" parameterType="User">
update t_user
<!--此处trim标签的作用和set一样,去除结尾的逗号-->
<trim prefix="set" suffixOverrides=",">
<if test="username!=null">
username=#{username},
</if>
<if test="password!=null">
password=#{password},
</if>
<if test="gender!=null">
gender=#{gender},
</if>
<if test="registTime!=null">
registTime=#{registTime}
</if>
</trim>
where id = #{id}
</update>
7.6 foreach标签
Integer deleteManyUser(List<Integer> ids)
<delete id="deleteManyUser" parameterType="java.util.List">
<!--delete from t_user where id in(x,x,x,x,x,x)-->
delete from t_user where id in
<!--collection表示遍历参数的类型,item表示每次遍历出的值,separator表示用逗号做分隔-->
<foreach collection="list" open="(" close=")" item="id9" separator=",">
#{id9}
</foreach>
</delete>
Integer insertManyUser(List<User> users)
<insert id="insertManyUser" parameterType="java.util.List">
<!--insert into t_user values(null,x,x,x,x)-->
insert into t_user values
<!--open和close不规则空着-->
<foreach collection="list" open="" close="" item="user9" separator=",">
(null,#{user9.username},#{user9.password},#{user9.gender},#{user9.registTime})
</foreach>
</insert>
八、缓存
8.1 一级缓存
8.2 二级缓存
<!--配置文件中二级缓存默认开启-->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
<!--mapper中被cache标签包裹的查询语句才能进入二级缓存-->
<cache>
<insert>...</insert>
<delete>...</delete>
<select>...</select>
<update>...</update>
</cache>
九、Druid连接池
<!--Druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.6</version>
</dependency>
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.datasource.pooled.PooledDataSourceFactory;
public class MyDruidDataSourceFactory extends PooledDataSourceFactory {
public MyDruidDataSourceFactory(){
this.dataSource = new DruidDataSource();//替换数据源
}
}
<!--数据库连接参数-->
<dataSource type="util.MyDruidDataSourceFactory">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</dataSource>
十、分页插件PageHelper
10.1 概念
10.2 访问与下载
10.3 使用步骤
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.10</version>
</dependency>
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
//假设要查寻出某张表所有的数据,使用PageHelper分页
//在调用查询方法的前一步使用PageHelper插件
//第一个参数表示查第几页,第二个参数表示没有显示几条数据
PageHelper.startPage(1, 2);
List<User> userList = mapper.findAll();
//封装list到 PageInfo对象中自动分页
PageInfo<User> userPageInfo = new PageInfo<>(userList);
十一、注解使用
//@Select @Update @Delete @Insert操作都是相同的
@Select("select id,username,password,gender,regist_time registTime from t_user where id=#{id}")
User queryUserById(Integer id);
//主键回填,写在@Insert上方
@Options(useGeneratedKeys = true,keyProperty = "id")
十二、${}和#{}
12.1 区别
十三、嵌套查询
13.1 概念
12.2 步骤
List<Employee> queryEmployeeByDeptId(@Param("dept_id") Integer dept_id);
<select id="queryEmployeeByDeptId" resultType="Employee">
select id,name,salary
from t_departments
where dept_id=#{dept_id}
</select>
Department queryDepartmentById(@Param("id") Integer id);
<resultMap id="department_result" type="Department">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<result column="location" property="location"></result>
<!--employee是主表实体类中的对象属性名-->
<!--嵌套queryEmployeeByDeptId方法查询-->
<!--queryEmployeeByDeptId方法查询所用的字段为外键,值与主表主键字段相同,column-->
<collection property="employee" ofType="Employee"
select="dao.EmployeeDao.queryEmployeeByDeptId" column="id">
</collection>
</resultMap>
<select id="queryDepartmentById" resultMap="department_result">
select id,name,location
from t_departments
where id=#{id}
</select>