MyBatis概念
mybatis是一个ORM框架,是一个基于Java的持久层框架。
mybatis会对jdbc的操作过程进行封装,使得开发者只需要关注SQL本身,而无需去花费精力去处理 注册驱动、获取链接、设置参数、结果集解析、 释放资源等工作,可以简化jdbc开发成本。
简单来讲,MyBatis是一个用于操作数据库的开源框架,(作用和传统的JDBC类似),它底层就是一个JDBC封装的组件。
mybatis就是对jdbc的操作过程进行封装,使得开发者只需要关注SQL。
MyBatis相关的概念
ORM:Object Relational Mapping
ORM是通过使用描述对象和数据库之间的映射关系的元数据,将程序中的对象持久化到关系型数据库中。是一种思想。
hibernate、mybatis都是对象关系映射的框架。
JPA:Java Persistence API
是Java持久化接口的意思,它是JavaEE关于ORM思想的一套标准接口,仅仅是一套接口,不是具体的实现。
mybatis架构
ps:MyBatis虽然实现了JPA但是它并不是一个完完全全的ORM组件,而是一个基于SQL开发的半ORM组件。
而Hibernate是一个完完全全的ORM组件,它是完全基于对象来操作数据库中的记录。
所以mybatis比hibernate更为简单。
MyBatis环境搭建
1.新建java项目,导入jar包mybatis-3.2.7.jar和 junit等等
2.在这里我配置了一个日志文件,打印日志(资源文件)
3.配置mybatis全局配置文件
这是一个壳,不要改(也许可能会改)
<?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>
这是内容
<!-- 运行环境: 与spring整合后就不需要了
default: 运行哪个环境,里面是id-->
<environments default="mysql">
<environment id="mysql">
<!-- 事务管理 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 数据源 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?
characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 加载映射文件 -->
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
以上是最简单的版本,后面会介绍更多的功能。
开始写功能例子
1.先写一个pojo类,也就是实体类(这个随便给你们个例子)
这是属性,需要生成get、set方法,有参、无参构造,再重写一下toString方法
2.写一个mapper.xml文件,这是一个映射文件,写sql语句的,需要在全局配置文件中配置(就是在mybatis.xml文件中配置<mapper></mappper>
,配置上面有)
<?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的作用:分割sql -->
<mapper namespace="UserMapper">
</mapper>
这是一个壳,namespace的作用就是如果有多个mapper,就用他来分辨。
而下面这个就是里面的内容
<!-- 入门程序:根据id查询用户信息
id:唯一的(本namespace下唯一),用于标识映射文件的sql,称为statement的id
parameterType:输入参数类型;支持的类型包括java基本类型、pojo对象、hashmap
resultType:输出结果类型;指定的为单条记录的类型,(也就是说如果返回多条记录,是单条记录的类型)
#{}:占位符 特点(注意):如果输入参数类型是基本类型的,则#{}里面可以是任意参数。或者是#{value}最规范,如果是pojo类型,那么必须和里面的变量名一致
-->
<select id="selectById" parameterType="int" resultType="com.cbb.pojo.User">
select * from user where id = #{id}
</select>
<!-- 模糊查询
${}使用的是sql拼接,没有进行sql注入的处理。应该少使用
如果输入参数是基本类型的,则${}里面只能是${value},
-->
<select id="selectByName" parameterType="String" resultType="com.cbb.pojo.User" >
<!-- select * from user where userName like '%${value}%' -->
select * from user where userName like CONCAT("%",#{username},"%")
</select>
<!-- 如果添加的方法有错误,以前的也不会执行 -->
<!-- 新增用户 -->
<insert id="addUser" parameterType ="com.cbb.pojo.User" useGeneratedKeys="true" keyProperty="id">
insert into user(username,birthday,sex,address) values(#{userName},#{birthday},#{sex},#{address})
</insert>
<!-- 修改 userName 必须和类里面的相同,因为是映射类里面的 -->
<update id="updateUser" parameterType="com.cbb.pojo.User">
update user set userName = #{userName}, sex = #{sex} where id = #{id}
</update>
<!-- 删除 -->
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
增删改查用不一样的标签,连模糊查询都有了(主要是为了防止sql注入做的特别演示,也就是用concat,而注释掉的有可能被注入)。里面的注释着重记一下。
3.写一个测试用例,写一个class就行。
然后这就是main方法,里面是全部流程
public static void main(String[] args) {
try {
//1.加载mybatis的运行环境 io流的方式读取全局配置文件
InputStream is = Resources.getResourceAsStream("mybatis.xml");
//2.创建会话工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.获取会话
SqlSession sqlSession = sqlSessionFactory.openSession();
//4.通过会话操作数据库
//第一个参数:statement的id 具体执行的sql 写法是:namespace.id
//第二个参数:值
User user = sqlSession.selectOne("UserMapper.selectById", 1);
System.out.println("user:"+user);
sqlSession.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
**动态代理对象调用 sqlSession.selectOne()和 sqlSession.selectList()是根据 mapper 接
口方法的返回值决定,如果返回 list 则调用 selectList 方法,如果返回单个对象则调用
selectOne 方法。**上面用的是selectOne(),下面有selectList()的例子
ps:下面这张图是使用junit插件,有兴趣可以了解一下,很简单,而且你肯定会用到,不论测试还是开发
public class UserMTest {
private SqlSession sqlSession;
@Before
public void init() throws IOException {
//初始化、加载环境、创建会话工厂、获取会话
//1.加载mybatis的运行环境 io流的方式读取全局配置文件
InputStream is = Resources.getResourceAsStream("mybatis.xml");
//2.创建会话工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.获取会话
sqlSession = sqlSessionFactory.openSession();
}
@Test
public void selectById() {
//4.通过会话操作数据库
//第一个参数:statement的id 具体执行的sql 写法是:namespace.id
//第二个参数:值
User user = sqlSession.selectOne("UserMapper.selectById", 1);
System.err.println("user:"+user);
}
/**
* 方法描述: 模糊查询用例
*/
@Test
public void selectByName() {
List<User> list = sqlSession.selectList("UserMapper.selectByName", "三");
System.err.println(list);
}
/**
* 方法描述: 新增用户测试用例
*/
@Test
public void addUser() {
User user = new User();
user.setUserName("jack");
user.setAddress("寨里");
user.setBirthday(new Date());
user.setSex("男");
int i = sqlSession.insert("UserMapper.addUser", user);
sqlSession.commit();
System.err.println(i);
//这里是一个特别的地方,我们在mapper.xml文件中设置的我们可以获取到他的id
System.err.println(user.getId());
}
@Test
public void delete() {
int i = sqlSession.delete("UserMapper.deleteUser", 52);
sqlSession.commit();
System.err.println("删除"+i);
System.out.println("aaaaa");
}
/**
* 方法描述:修改一个用户信息
*/
@Test
public void updateUser() {
User user = new User();
user.setId(51);
user.setUserName("rose");
user.setSex("女");
int i = sqlSession.update("UserMapper.updateUser", user);
sqlSession.commit();
System.err.println(i);
}
@After
public void after() {
sqlSession.close();
}
}
这是引入的包
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
import org.apache.ibatis.annotations.Delete;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;
注意:session增删改操作后要commit提交,如果不用commit提交,不会报错,但数据库不会改变。所有操作最后都要close关闭session。增删改查也调用的不一样的方法
例子到此结束
——————————————————
你想想,每次都要初始化、加载环境、创建会话工厂、获取会话,岂不是很麻烦,所以我们可以把他封装到一个类中
创建工具类
package com.cbb.utils;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
/**
* 类描述:实现会话工厂的单例模式
* 作者: 地铁与人海
* 创建日期:2019年3月7日
* 修改人:
* 修改日期:
* 修改内容:
* 版本号: 1.0.0
*/
public class SqlSessionFactoryUtil {
private static SqlSessionFactory sqlSessionFactory;//会话工厂
static {
System.err.println("static静态代码块");
//初始化、加载环境、创建会话工厂、获取会话
//1.加载mybatis的运行环境 io流的方式读取全局配置文件
InputStream is;
try {
is = Resources.getResourceAsStream("mybatis.xml");
//2.创建会话工厂
sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 方法描述:获取会话工厂
* @return
*/
public static SqlSessionFactory getSqlSessionFactory() {
return sqlSessionFactory;
}
}
这就是我创建的工具类,就是创建着玩,用起来也就省了一两步
这是使用
public class LoginTest {
private SqlSession sqlSession;
@Before
public void init() {
sqlSession = SqlSessionFactoryUtil.getSqlSessionFactory().openSession();
}
/**
* 方法描述: 模糊查询用例
*/
@Test
public void selectByName() {
List<User> list = sqlSession.selectList("t_UserMapper.selectByName", "a");
System.err.println(list);
}
}
会话工厂与会话的简介
SqlSessionFactory: 会话工厂。通过全局配置文件创建的,由SqlSessionFactoryBuild对象创建。
作用:创建会话。
特点:会话工厂一旦创建,就会在应用程序的执行期间一直存在。我们就不需要重复的来创建这个 会话工厂了。所
以我们应该 把它的实现方式设计为 单例模式的。
SqlSession: 会话。 作用:操作数据库。
特点:线程不安全的。应该把会话声明为局部的。
全局配置文件的其他配置
起别名
这样,我们可以将mapper里面的resultType=“com.cbb.pojo.User"改为你起的名字"user”
功能照常运行。
批量加载映射文件
上面是只加载一个mapper配置文件
下面是批量加载配置文件,加载一整个包里面的配置文件
下面这个我没用过,是粘贴过来的,有引用出处。
我一直以为上面那张图片的地址是我复制时的网址,今天想回去看一下发现那是我的。
上面这个是加在mybatis的配置文件中的,
当你得pojo对象的字段名和数据库中的表的字段名不一致时,你使用select *
就会只查出相符的字段,此时需要使用起别名的方法进行查询。
一般不一样的原因在于,字段名是由两个单词组成的,比如在java中是userName
,而在数据库中是user_name
,
此时如果我们想使用select*
,可以在配置上加上上面这个配置,他自动会给你转换java和数据库的字段名,就不需要起别名了。
还有下面这一些配置
<settings>
<!-- 全局映射器启用缓存 -->
<setting name="cacheEnabled" value="true"/>
<!-- 查询时,关闭关联对象即时加载以提高性能 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 对于未知的SQL查询,允许返回不同的结果集以达到通用的效果 -->
<setting name="multipleResultSetsEnabled" value="true"/>
<!-- 允许使用列标签代替列名 -->
<setting name="useColumnLabel" value="true"/>
<!-- 不允许使用自定义的主键值(比如由程序生成的UUID 32位编码作为键值),数据表的PK生成策略将被覆盖 -->
<setting name="useGeneratedKeys" value="false"/>
<!-- 给予被嵌套的resultMap以字段-属性的映射支持 FULL,PARTIAL -->
<setting name="autoMappingBehavior" value="PARTIAL"/>
<!-- Allows using RowBounds on nested statements -->
<setting name="safeRowBoundsEnabled" value="false"/>
<!-- Enables automatic mapping from classic database column names A_COLUMN to camel case classic Java property names aColumn. -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- MyBatis uses local cache to prevent circular references and speed up repeated nested queries. By default (SESSION) all queries executed during a session are cached. If localCacheScope=STATEMENT
local session will be used just for statement execution, no data will be shared between two different calls to the same SqlSession. -->
<setting name="localCacheScope" value="SESSION"/>
<!-- Specifies the JDBC type for null values when no specific JDBC type was provided for the parameter. Some drivers require specifying the column JDBC type but others work with generic values
like NULL, VARCHAR or OTHER. -->
<setting name="jdbcTypeForNull" value="OTHER"/>
<!-- Specifies which Object's methods trigger a lazy load -->
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
<!-- 设置关联对象加载的形态,此处为按需加载字段(加载字段由SQL指 定),不会加载关联表的所有字段,以提高性能 -->
<setting name="aggressiveLazyLoading" value="false"/>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<typeAliases>
<!-- 注:model表对象配置,请按照 model 包 中的顺序进行录入,并做好注释. -->
</typeAliases>
<plugins>
<plugin interceptor="com.github.abel533.mapperhelper.MapperInterceptor">
<!--主键自增回写方法,默认值MYSQL,详细说明请看文档 -->
<property name="IDENTITY" value="MYSQL" />
<!--通用Mapper接口,多个通用接口用逗号隔开 -->
<property name="mappers" value="com.github.abel533.mapper.Mapper" />
</plugin>
</plugins>
上面我也不太懂,多见谅。
如有疑问,可以问我
END