MyBatis是什么
MyBatis是一个ORM的数据库持久化框架。
一.创建一个项目,导包
二.准备相应的表、domain、dao、测试
三.入门实现
3.1实现步骤分析
①获取SqlSessionFactory
1 我们需要准备一个核心的Mybatis-config.xml文件
2 拿到SqlSessionFactory之前需要读取核心的xml配置文件
3 需要构造者(SqlSessionFactoryBuilder)来创建它
②映射文件准备
③通过SqlSessionFactory获取SqlSession执行映射SQL
3.2实现
<?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>
<!--引入jdbc.propeties文件-->
<properties resource="jdbc.properties" />
<typeAliases>
<!-- 单个配置:练习 -->
<!-- <typeAlias type="cn.itsource.domain.User" alias="user"></typeAlias>-->
<!-- 包的配置:项目,添加了包之后,类名就是别名 -->
<package name="cn.itsource.domain"></package>
<package name="cn.itsource.query"></package>
</typeAliases>
<!-- 环境们 (很多环境的意思)
default:默认使用哪一个环境(必需对应一个环境的id)
-->
<environments default="development">
<!--
一个环境 id:为这个环境取唯一一个id名称
-->
<environment id="development">
<!--
事务管理 type:JDBC(支持事务)/MANAGED(什么都不做)
-->
<transactionManager type="JDBC" />
<!-- 数据源, 连接池 type(POOLED):MyBatis自带的连接池 -->
<dataSource type="POOLED">
<!-- 连接数据库的参数 -->
<property name="driver" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!-- 这个mappers代表的是相应的ORM映射文件 -->
<mappers>
<mapper resource="cn/itsource/domain/UserMapper.xml" />
</mappers>
</configuration>
3.3 映射文件
①我们的映射文件(就是我们的mapper文件)一般情况下是和它对应的domain实体类在同一个层级
② 这个映射文件的名称一般叫做 XxxMapper.xml (Xxx代表的是实体类名称)
③ namespace的名称为了确定唯一性,请大家根据我的要求取名
<?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">
<!-- orm框架 sql的映射
namespace:命名空间 namespace路径+ id值
namespace怎么配置 包名.接口名 + queryAll
-->
<mapper namespace="cn.itsource.dao.IUserDao">
<!-- 查询 queryAll()
resultType 返回类型
-->
<select id="queryAll" resultType="cn.itsource.domain.User">
select * from t_user
</select>
<select id="queryOne" parameterType="long" resultType="User">
select * from t_user where id=#{id}
</select>
<!--新增-->
<select id="save" parameterType="User">
insert into t_user(name) values(#{name})
</select>
<!--修改-->
<update id="update" parameterType="User">
update t_user set name=#{name} where id=#{id}
</update>
<!--删除-->
<delete id="delete" parameterType="long">
delete from t_user where id=#{id}
</delete>
<sql id="TopSql">
<if test="name!=null">
and name like #{name}
</if>
<if test="age!=null">
and age = #{age}
</if>
</sql>
<select id="queryList" parameterType="userQuery" resultType="User">
select * from t_user
<where>
<include refid="TopSql"></include>
</where>
</select>
<!--批量删除-->
<delete id="deleteBatch" parameterType="list">
delete from t_user where id in
<foreach collection="list" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
<!-- 批量新增-->
<insert id="saveBatch" parameterType="list">
insert into t_user(name) values
<foreach collection="list" item="user" separator="," >
(#{user.name})
</foreach>
</insert>
</mapper>
3.4其他实现
package cn.itsource.dao;
import cn.itsource.domain.User;
import cn.itsource.query.UserQuery;
import java.io.IOException;
import java.util.List;
public interface IUserDao {
void save(User user) throws IOException;
void update(User user) throws IOException;;
void delete(Long id) throws IOException;
List<User> queryAll() throws IOException;
User queryOne(Long id)throws IOException;
//批量删除
void deleteBatch(List ids) throws Exception;
//批量新增
void saveBatch(List users) throws Exception;
//高级查询方法
List<User> queryList(UserQuery userQuery) throws Exception;
}
package cn.itsource.dao.impl;
import cn.itsource.dao.IUserDao;
import cn.itsource.domain.User;
import cn.itsource.query.UserQuery;
import cn.itsource.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import java.io.IOException;
import java.util.List;
public class UserDaoImpl implements IUserDao{
@Override
public void save(User user) throws IOException {
SqlSession sqlSession = MybatisUtils.INSTANCE.getSqlSession();
sqlSession.insert("cn.itsource.dao.IUserDao.save",user);
sqlSession.commit();
}
@Override
public void update(User user) throws IOException {
SqlSession sqlSession = MybatisUtils.INSTANCE.getSqlSession();
sqlSession.update("cn.itsource.dao.IUserDao.update",user);
sqlSession.commit();
}
@Override
public void delete(Long id) throws IOException {
SqlSession sqlSession = MybatisUtils.INSTANCE.getSqlSession();
sqlSession.delete("cn.itsource.dao.IUserDao.delete",id);
sqlSession.commit();
}
@Override
public List<User> queryAll() throws IOException {
SqlSession sqlSession = MybatisUtils.INSTANCE.getSqlSession();
List<User> users = sqlSession.selectList("cn.itsource.dao.IUserDao.queryAll");
return users;
}
@Override
public User queryOne(Long id) throws IOException {
SqlSession sqlSession = MybatisUtils.INSTANCE.getSqlSession();
User user = sqlSession.selectOne("cn.itsource.dao.IUserDao.queryOne",id);
return user;
}
@Override
public void deleteBatch(List ids) throws Exception {
SqlSession sqlSession = MybatisUtils.INSTANCE.getSqlSession();
sqlSession.delete("cn.itsource.dao.IUserDao.deleteBatch",ids);
sqlSession.commit();
}
@Override
public void saveBatch(List users) throws Exception {
SqlSession sqlSession = MybatisUtils.INSTANCE.getSqlSession();
sqlSession.insert("cn.itsource.dao.IUserDao.saveBatch",users);
sqlSession.commit();
}
@Override
public List<User> queryList(UserQuery userQuery) throws Exception {
SqlSession sqlSession = MybatisUtils.INSTANCE.getSqlSession();
List<User> users = sqlSession.selectList("cn.itsource.dao.IUserDao.queryList", userQuery);
return users;
}
}
测试类
package cn.itsource.test;
import cn.itsource.dao.impl.UserDaoImpl;
import cn.itsource.domain.User;
import cn.itsource.query.UserQuery;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
public class MybatisTest {
@Test
public void test()throws Exception{
List list = new UserDaoImpl().queryAll();
list.forEach(e->{
System.out.println(e);
});
}
@Test
public void testSave()throws Exception{
User user = new User();
user.setName("格林");
new UserDaoImpl().save(user);
System.out.println(user);
}
@Test
public void testUpdate()throws Exception {
User user = new User();
user.setId(12L);
user.setName("利欧路");
new UserDaoImpl().update(user);
}
@Test
public void testDelete() throws Exception{
List<Long> ids = Arrays.asList(10L, 11L, 12L, 13L);
new UserDaoImpl().delete(13L);
}
@Test
public void test2() throws Exception{
System.out.println(new UserDaoImpl().queryOne(1L));
}
@Test
public void testQuerylist()throws Exception{
UserQuery userQuery = new UserQuery();
userQuery.setName("%斯%");
userQuery.setAge(35);
List<User> users = new UserDaoImpl().queryList(userQuery);
users.forEach(e->{
System.out.println(e);
});
}
@Test
public void testDeleteBatch()throws Exception{
List<Long> ids = Arrays.asList(12L,14L,15L);
new UserDaoImpl().deleteBatch(ids);
}
@Test
public void testSaveBatch()throws Exception{
List<User> users = Arrays.asList(new User("蔡徐坤"),
new User("吴亦凡"),
new User("鹿晗"));
new UserDaoImpl().saveBatch(users);
}
}
四、抽取Mybatis CRUD-工具类
4.1抽取理论
SqlSessionFactoryBuilder
建造者模式:我们最后拿到的这个对象是非常复杂的. 用这个建造者就它先为我们把这些复杂的代码完成. 这个类可以被实例化,使用和丢弃。一旦创建了SqlSessionFactory后,这个类对象就不需要存在了。因此SqlSessionFactoryBuilder实例的最佳范围是方法范围(也就是本地方法变量)。
SqlSessionFactory
一旦被创建,SqlSessionFactory应该在你的应用执行期间都存在。没有理由来处理或重新创建它。使用SqlSessionFactory的最佳实践是在应用运行期间不要重复创建多次。这样的操作将被视为是非常糟糕的。因此SqlSessionFactory的最佳范围是应用范围。有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。然而这两种方法都不认为是最佳实践。
SqlSession
每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能被共享,也是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段甚至是实例字段中。也绝不能将SqlSession实例的引用放在任何类型的管理范围中,比如Serlvet架构中的HttpSession。如果你现在正用任意的Web框架,要考虑SqlSession放在一个和HTTP请求对象相似的范围内。换句话说,基于收到的HTTP请求,你可以打开了一个SqlSession,然后返回响应,就可以关闭它了。关闭Session很重要,
抽取
package cn.itsource.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.Reader;
public enum MybatisUtils {
INSTANCE;
private static SqlSessionFactory sqlSessionFactory;
static {
Reader reader = null;
try {
reader = Resources.getResourceAsReader("MyBatis-Config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("解析文件出错"+e.getMessage());
}
}
public SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
五、Mybtis使用细节
<!--
parameterType:需要传入我们的对象
useGeneratedKeys: 是否需要主键
keyColumn:主键所在的列
keyProperty:对象中的属性(代表主键的那个属性)
-->
<insert id="save" parameterType="cn.itsource.domain.Product"
useGeneratedKeys="true"
keyColumn="id"
keyProperty="id"
>
insert into product (productName,dir_id,salePrice,supplier,brand,cutoff,costPrice)
values (#{productName},#{dir_id},#{salePrice},#{supplier},#{brand},#{cutoff},#{costPrice})
</insert>
六.查看MyBatis运行日志
在使用MyBatis的很多时候,我们需要把日志打印出来,帮助我们进行分析与排错。特别是大家现在学习阶段,要求大家都MyBatis的日志打开。
# 日志输出级别 输出到控制
log4j.rootLogger=ERROR, stdout
#log4j.rootLogger=NONE
log4j.logger.cn.itsource=TRACE
# 输出到控制台的配置信息
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
# 输出到控制台的 格式类
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
七.在MyBatis中别名
7.1自定义别名
<typeAliases>
<!-- 单个配置:练习 -->
<typeAlias type="cn.itsource.mybatis.a_crud.Dept" alias="Dept" />
<!-- 包的配置:项目,添加了包之后,类名就是别名 -->
<package name="cn.itsource.mybatis.a_crud" />
</typeAliases>
7.2#与$区别
7.2.1 #{OGNL表达式}
MyBatis会把这个表达式使用?(占位符)替换,作为一个sql参数使用:推荐使用
比如:
定义SQL: select * from t_user where name = #{name}
最终SQL: select * from t_user where name = ?
7.2.2 ${OGNL表达式}
MyBatis会把这个表达式的值替换到sql中,作为sql的组成部分; 把获取到值直接拼接SQL,该方式主要用于程序拼接SQL;
比如:
定义SQL: select id,name,password from t_user where name = nameandpassword=
nameandpassword={password}
最终SQL: select id,name,password from t_user where name=“test” or “1=1” and password=“test” 出现sql注入
除了要拼接sql结构体要用$(是直接拼接sql),其他都用#,因为用#会替换为?,最终通过prepareStament来设置参数,不会有sql注入问提。
八.常用的动态SQL
MyBatis 的一个强大的特性之一通常是它的动态 SQL 能力。如果你有使用 JDBC 或其他
相似框架的经验,你就明白条件地串联 SQL 字符串在一起是多么的痛苦,确保不能忘了空
格或在列表的最后省略逗号。动态 SQL 可以彻底处理这种痛苦。