SpringStudy09-Mybatis02-Mybatis理论与实践
1.1 Mybatis 核心组件
Overview
SqlSessionFactoryBuilder(构造器):他会根据配置信息或者代码生成SqlSessionFactory(工厂接口)
SqlSessionFactory:依靠工厂来生成SqlSession(会话)
SqlSession:是一个即可以发送SQL去执行并返回结果,也可以获取Mapper的接口。
SQL Mapper:它是MyBatis新设计的组件,他是由一个Java接口和XML构成的,需要给出对应的SQL和映射规则。它负责发送SQL去执行,并返回结果。
每个MyBatis的应用都是以SqlSessionFactory的实例为中心的,类似于JDBC的Connection对象。MyBatis提供了两种模式去创建SqlSessionFactory,一种是XML配置,另一种是代码的方式。使用配置文件可以避免硬编码,方便日后配置人员的修改和避免重复编译代码。
Mybatis中由一个Configuration对象,并存在于整个生命周期,以便重复读取。我们可以解析一次配置的XML文件保存到Configuration类对象中。
SqlSessionFactory接口由两个实现类,目前Mybatis中使用的是DefaultSqlSessionFactory
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核心配置文件-->
<configuration>
<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://localhost:3306/mybatis-study?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="com.dao.UserMapper"/>
</mappers>
</configuration>
SqlSession 是一个接口类,它类似于你们公司的前台客服美女,真正干活的Executor接口。在Mybatis中SqlSession接口的实现类由两个:DefaultSqlSession和SqlSessionManger,这类似于Connection接口,我们需要保证每次用完正确的关闭它。
映射器
映射器是由Java接口和XML文件共同组成的,它的作用如下:
定义参数类型
描述缓存
描述SQL语句
定义查询结果和POJO的映射对象。
用XML文件配置实现Mapper
使用XML文件配置是MyBatis实现Mapper的首选方式。它是有一个Java接口和一个XML文件构成。
设置Java接口
public interface UserMapper {
List<User> getUserList();
}
给出映射的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">
<!--namespace=绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.dao.UserMapper">
<!--select查询语句-->
<select id="getUserList" resultType="com.pojo.User">
select * from user
</select>
</mapper>
这个文件是我们在配置mybatis-config.xml中配置了的,所以Mybatis会读取这个文件,生成映射器。
定义了一个命名空间为UserMapper的SQL mapper这个命名空间和我们定义的接口的全限定名是一致的。
写了具体的sql语句。
配置具体Pojo类
public class User {
private int id;
private String name;
private String pwd;
public User() {
}
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
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 String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
到此,我们来看看具体的Mybatis流程。
@Test
public void test1() throws IOException {
//加载mybatis配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//生成SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//打开SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取映射器Mapper
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//执行SQL
List<User> userList = userMapper.getUserList();
for (User user : userList) {
System.out.println(user);
}
//关闭SqlSession
sqlSession.close();
}
1.2 生命周期
1.1 SqlSessionFactoryBuilder
SqlSessionFactoryBuilder 是利用XML或者Java编码获得资源来构建SqlSessionFactory的,它的作用就是构建器,一旦构建了SqlSessionFactory,它的作用就已经完结了,应该立即回收。
1.2 SqlSessionFactory
SqlSessionFactory 的作用是创建SqlSession, SqlSession就是一个会话,每次应用程序需要访问数据库,我们就要通过SqlSessionFactory创建,所以SqlSessionFactory应该在MyBatis应用的整个生命周期中。但是如果我们多次创建同一个数据库的SqlSessionFactory,每次创建都会打开更多的连接资源,因此SqlSessionFactory应该果断采用单例模式。
1.3 SqlSession
SqlSession是一个会话,它的生命周期应该是在请求数据库处理事务的过程中。他是一个线程不安全的对象,在设计多线程的时候,我们应该特别的当心。并且我们往往需要通过finally语句块来保证关闭SqlSession.
1.4 Mapper
Mapper是一个接口,他没有任何实现类,它的作用就是发送SQL,返回我们需要的结果,或修改数据库的数据,因此他应该在一个SqlSession事务方法之内.
1.3 CRUD
新建一个Module,从头开始配置文件。数据库已经在上一节配置完毕了。
在com.pojo包下 新建pojo 映射类User
package com.pojo;
public class User {
private int id;
private String name;
private String pwd;
public User() {
}
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
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 String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
在dao层 配置 映射器接口和xml文件,注意这两个名字必须一样UserMapper UserMapper.xml
package com.dao;
import com.pojo.User;
import java.util.*;
public interface UserMapper {
//查询全部用户
List<User> selectUser();
//根据id查询用户
User selectUserById(int id);
//添加一个用户
int addUser(User user);
//修改一个用户
int updateUser(User user);
//根据id删除用户
int deleteUser(int id);
}
<?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.dao.UserMapper">
<!--select查询语句-->
<select id="selectUser" resultType="com.pojo.User">
select * from user
</select>
<select id="selectUserById" resultType="com.pojo.User">
select * from user where id = #{id}
</select>
<insert id="addUser" parameterType="com.pojo.User">
insert into user (id,name,pwd) values (#{id},#{name},#{pwd})
</insert>
<update id="updateUser" parameterType="com.pojo.User">
update user set name=#{name},pwd=#{pwd} where id = #{id}
</update>
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
</mapper>
在resource里编写mybatis配置文件: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">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis-study?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="com.dao.UserMapper"/>
</mappers>
</configuration>
编写MybatisUtils工具,单例生成SqlSessionFactory
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(){
return sqlSessionFactory.openSession();
}
}
测试
import com.dao.UserMapper;
import com.pojo.User;
import com.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class MyTest {
@Test
public void selectTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.selectUserById(1);
System.out.println(user);
sqlSession.close();
}
@Test
public void insertTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = new User(4, "admin", "admin");
int i = userMapper.addUser(user);
System.out.println(i);
sqlSession.commit(); //提交事务,重点!不写的话不会提交到数据库
sqlSession.close();
}
@Test
public void updateTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = new User(4, "admin111", "admin");
int i = userMapper.updateUser(user);
System.out.println(i);
sqlSession.commit(); //提交事务,重点!不写的话不会提交到数据库
sqlSession.close();
}
@Test
public void deleteTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int i = userMapper.deleteUser(1);
System.out.println(i);
sqlSession.commit(); //提交事务,重点!不写的话不会提交到数据库
sqlSession.close();
}
}
1.4 细节
查询参数导入
直接在方法中传递参数
在UserMapper接口继续添加方法
//通过密码和名字查询用户
User selectUserByNP(@Param("username") String username, @Param("pwd") String pwd);
<select id="selectUserByNP" resultType="com.pojo.User">
select * from user where name = #{username} and pwd = #{pwd}
</select>
万能的Map
User selectUserByNP2(Map<String,Object> map);
<select id="selectUserByNP2" parameterType="map" resultType="com.pojo.User">
select * from user where name = #{username} and pwd = #{pwd}
</select>
测试
@Test
public void Test1(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.selectUserByNP("Jack", "123456");
System.out.println(user);
}
@Test
public void Test2(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
Map<String, Object> map = new HashMap<String, Object>();
map.put("username","Jack");
map.put("pwd","123456");
User user = userMapper.selectUserByNP2(map);
System.out.println(user);
}
模糊查询
List<User> selectLikeName(@Param("username") String username);
<select id="selectLikeName" resultType="com.pojo.User">
select * from user where name like #{username}
</select>
测试
@Test
public void selectLikeTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.selectLikeName("%J%");
for (User user : users) {
System.out.println(user);
}
}
typeAliases优化
在Mybatis-config.xml 中添加包扫描
<typeAliases>
<package name="com.pojo"/>
</typeAliases>
在User添加注解
@Alias("User")
public class User {
这样在Mapper.xml中不需要写完全的类的地址了
<select id="selectUserById" resultType="user">
select * from user where id = #{id}
</select>
自动映射
mybatis会根据这些查询的列名(会将列名转化为小写,数据库不区分大小写) , 去对应的实体类中查找相应列名的set方法设值
如果在pojo中找不到set字段的方法,该属性值就会报null
可以使用ResultMap手动映射
<resultMap id="UserMap" type="User">
<!-- id为主键 -->
<id column="id" property="id"/>
<!-- column是数据库表的列名 , property是对应实体类的属性名 -->
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
<select id="selectUserById" resultMap="UserMap">
select id , name , pwd from user where id = #{id}
</select>
1.5 注解开发
利用注解开发就不需要mapper.xml映射文件了
我们可以直接定义Mapper接口
@Select("select id,name,pwd password from user")
public List<User> getAllUser();
//根据id查询用户
@Select("select * from user where id = #{id}")
User selectUserById(@Param("id") int id);
//添加一个用户
@Insert("insert into user (id,name,pwd) values (#{id},#{name},#{pwd})")
int addUser(User user);
//修改一个用户
@Update("update user set name=#{name},pwd=#{pwd} where id = #{id}")
int updateUser(User user);
//根据id删除用
@Delete("delete from user where id = #{id}")
int deleteUser(@Param("id")int id);
#与$的区别
关于@Param https://blog.youkuaiyun.com/a22222259/article/details/90722112