Mybatis
学习Mybatis就要学会查看官网,官网地址如下:<MyBatis中文网 >
1、简介
1.1什么是Mybatis
- MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。
- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
- MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
1.2如何获得Mybatis
-
通过Maven仓库直接获取
<dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> </dependencies>
-
github上获取
-
中文文档
1.3持久化
数据持久化
- 持久化就是将程序的数据在持久状态和瞬时状态转化的过程
- 内存:断电即失
- 数据持久化的两种方式:数据库(jdbc),io文件持久化
为什么需要持久化?
-
因为内存断电即失,有一些对象我们不能让他丢掉,需要持久化将他存储起来。
-
内存太贵了
1.4持久层
三层结构:Dao层,Service层,Controller层
- 持久层是完成持久化工作的代码块
- 层界限十分明显
1.5为什么需要Mybatis
-
帮助程序员将数据存入到数据库中
-
传统的JDBC代码太复杂了,为了把它简化,形成一个框架,实现自动化。
-
不用Mybatis也可以,只是用了Mybatis框架可以更容易上手
-
优点
- sql和代码的分离,提高可维护性
- 提供映射标签,支持对象与数据库的orm字段关系映射
- 提供对象关系映射标签,支持对象关系组建维护
- 提供xml标签,支持编写动态sql
2、第一个Mybatis程序
思路:搭建环境–>导入Mybatis–>编写代码–>测试
2.1搭建环境
搭建数据库
create database Mybatis;
use Mybatis;
update table user(
id int(20) not null primary key,
name varchar(30) default null,
password int(20) default null
)ENGINE=INNODB DEFAULT CHARSET=UTF8;
alter table user modify column password varchar(20);
insert into user values
(1,'狂神','123456'),
(2,'狂神','123456'),
(3,'狂神','123456')
#####2.2搭建项目
1、新建一个普通的maven项目
2、导入依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>Mybatis</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Mybatis</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!--JUNIT驱动-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!--Mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
</dependency>
<!--Mybatis驱动-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
</dependencies>
</project>
2.3创建模块
- 编写mybatis的核心配置文件
- 编写mybatis的工具类
package com.kuang.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 MybatisUtil {
private static SqlSessionFactory sqlSessionFactory;
//静态代码块,按照官方文档填写
static{
//第一步:获取SqlSessionFactory对象
try {
//获取配置资源
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//通过sqlSessionFactory获取SqlSession对象
public static SqlSession getSession(){
return sqlSessionFactory.openSession();
}
}
2.4编写代码
-
实体类
根据数据库中的数据元素编写类的属性。
package com.kuang.pojo; public class User { private int id; private String name; private String pwd; @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", pwd='" + pwd + '\'' + '}'; } 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; } }
-
Dao接口
Dao接口定义了sql语句的实现方法
package com.kuang.dao; import com.kuang.pojo.User; import java.util.List; public interface UserDao { List<User> getUserList(); }
-
接口实现类
在Mapper配置文件中直接配置对应接口信息,查询的数据库,返回结果的类型等等,侧面实现接口方法,不用重复编写代码
<?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.kuang.dao.UserDao"> <!--id对应所要实现的接口方法,resultType对象所要返回的数据类型--> <select id="getUserList" resultType="com.kuang.pojo.User"> select * from mybatis.user </select> </mapper>
#####2.5测试
报错提示:org.apache.ibatis.binding.BindingException: Type interface com.kuang.dao.UserDao is not known to the MapperRegistry.
这是因为pom.xml文件中maven没有配置我们定义的Dao层文件。
####3、CRUD
- id:就是对应的namespace中的方法名
- resultType:Sql语句执行的返回值
- parameterType:参数的类型
步骤:
- 1、编写接口
- 2、配置xml文件实现接口,编写对应sq语句
- 3、测试,增删改要注意提交事务
3.1接口文件
package com.kuang.dao;
import com.kuang.pojo.User;
import java.util.List;
public interface UserMapper {
//查询全部用户
List<User> getUserList();
//根据ID查询用户
User getUserById(int id);
//新增用户
Integer addUser(User user);
//修改用户
Integer updateUser(User user);
//删除用户
void deleteUser(int id);
}
3.2实现接口
<?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.kuang.dao.UserMapper">
<!--id对应所要实现的接口方法,resultType对象所要返回的数据类型-->
<select id="getUserList" resultType="com.kuang.pojo.User">
select * from mybatis.user
</select>
<select id = "getUserById" resultType="com.kuang.pojo.User" parameterType="int">
select * from mybatis.user where id =#{id}
</select>
<select id="addUser" parameterType="com.kuang.pojo.User" resultType="java.lang.Integer">
insert into user (id,name,password) values (#{id},#{name},#{password});
</select>
<update id="updateUser" parameterType="com.kuang.pojo.User" >
update user set name = #{name},password = #{password} where id =#{id}
</update>
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
</delete>
</mapper>
3.3测试类
package com.kuang.dao;
import com.kuang.pojo.User;
import com.kuang.utils.MybatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.testng.annotations.Test;
import java.util.List;
public class UserDaoTest {
@Test
public void test(){
//第一步:获得 SqlSession对象
SqlSession sqlSession=MybatisUtil.getSession();
//执行sql
UserMapper userDao=sqlSession.getMapper(UserMapper.class);
List<User> userList = userDao.getUserList();
for(User user : userList){
System.out.println(user);
}
sqlSession.close();
}
@Test
public void getUserById(){
SqlSession sqlSession = MybatisUtil.getSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.getUserById(1);
System.out.println(user);
sqlSession.close();
}
//增删改需要提交事务
@Test
public void addUser(){
SqlSession sqlSession = MybatisUtil.getSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
Integer res=userMapper.addUser(new User(4,"哈哈","123456"));
if(res==null)
System.out.println("insert ok");
else System.out.println("insert failed");
//提交事务
sqlSession.commit();
sqlSession.close();
}
@Test
public void updateUser() {
SqlSession sqlSession = MybatisUtil.getSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
Integer res = userMapper.updateUser(new User(4, "哈哈", "12345"));
sqlSession.commit();
sqlSession.close();
}
@Test
public void deleteUser(){
SqlSession sqlSession = MybatisUtil.getSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
userMapper.deleteUser(2);
sqlSession.commit();
sqlSession.close();
}
}
3.4万能的Map(写项目较好)
假设实体类或者数据库中的表,字段或者参数过多,我们应当考虑使用map
在接口方法中,参数直接传递Map;
User selectUserByNP2(Map<String,Object> map);
编写sql语句的时候,需要传递参数类型,参数类型为map
<select id="selectUserByNP2" parameterType="map" resultType="com.kuang.pojo.User">
select * from user where name = #{username} and pwd = #{pwd}
</select>
在使用方法的时候,Map的 key 为 sql中取的值即可,没有顺序要求
Map<String, Object> map = new HashMap<String, Object>();
map.put("username","小明");
map.put("pwd","123456");
User user = mapper.selectUserByNP2(map);
4、配置解析
4.1核心配置文件
- mybatis-config.xml
- Mybatis的配置文件包含了会深深影响Mybatis行为的设置和属性信息
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
4.2环境配置(environment)
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="..." value="..."/>
</transactionManager>
<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>
- 配置MyBatis的多套运行环境,将SQL映射到多个不同的数据库上,必须指定其中一个为默认运行环境(通过default指定)
4.3Properties优化
数据库这些属性都是可外部配置且可动态替换的,既可以在典型的 Java 属性文件中配置,亦可通过 properties 元素的子元素来传递 。
第一步 :在资源目录下新建一个db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8
username=root
password=123456
第二步 : 将文件导入properties 配置文件
<configuration>
<!--导入properties文件-->
<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="mapper/UserMapper.xml"/>
</mappers>
</configuration>
- 可以直接引入外部文件
- 可以在其中增加一些属性配置
- 如果两个文件有同一个字段,优先使用外部配置文件
4.4类型别名(typeAliases)
- 类型别名是为Java类型设置一个短的名字
- 存在的意义仅在于用来减少类完全限定名的冗余
<!--配置别名,注意顺序-->
<typeAliases>
<typeAlias type="com.kuang.pojo.User" alias="User"/>
</typeAliases>
也可以指定一个包名,Mybatis会在包名下面搜索需要的java Bean,比如扫描实体类的包,意思就是当包名为User时,我们可以使用包的小写别名“user”。
也可以在实体上增加注解,来添加类的别名
@Alias("user")
public class User{}
4.5设置
设置查看官方文档
-
懒加载
-
日志实现
-
缓存开启关闭
-
一个配置完整的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>
4.6映射器(mappers)
MapperRegistry:注册绑定我们的mapper文件
方式一:文件定位
<mappers>
<mapperresource="coom/kuang/dao/UserMapper.xml"/>
</mappers>
方式二:使用class文件绑定注册
<mappers>
<mapper class="com.kuang.dao.UserMapper"/>
</mappers>
注意点:
- 接口和他的Mapper配置文件必须同名
- 接口和他的Mapper配置文件必须在同一个包下
方式三:使用扫描包进入诸如绑定
<mappers>
<package name="com.kuang.dao"/>
</mappers>
4.7作用域和生命周期
生命周期和作用域时非常重要的。
“lazyLoadTriggerMethods” value=“equals,clone,hashCode,toString”/>
##### 4.6映射器(mappers)
MapperRegistry:注册绑定我们的mapper文件
方式一:文件定位
```xml
<mappers>
<mapperresource="coom/kuang/dao/UserMapper.xml"/>
</mappers>
方式二:使用class文件绑定注册
<mappers>
<mapper class="com.kuang.dao.UserMapper"/>
</mappers>
注意点:
- 接口和他的Mapper配置文件必须同名
- 接口和他的Mapper配置文件必须在同一个包下
方式三:使用扫描包进入诸如绑定
<mappers>
<package name="com.kuang.dao"/>
</mappers>
4.7作用域和生命周期
生命周期和作用域时非常重要的。
- sqlSessionFactoryBuilder
- 一旦创建了sqlSessionFactory就不需要了
- 局部变量
- sqlSessionFactory
- 可以理解为数据库连接池
- 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例
- 最佳作用域是应用作用域
- 最简单的是使用单例模式或者静态单例模式
- sqlSession
- 连接到连接池的一个请求
- SqlSession的实例不是线程安全的,因此是不能被共享的
- 最佳作用域是调用作用域或者方法作用域
- 用完之后需要赶紧关闭
5、ResultMap
解决属性名和字段名不一致的问题
数据库中的字段和定义类中的字段不一样
解决办法
-
起别名
<select id="selectUserById" resultType="User"> select id , name , pwd as password from user where id = #{id} </select>
-
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>
6、日志
6.1日志工厂
如果一个数据库操作出现了异常,我们需要排错。
- SLF4J
- Apache Commons Logging
- Log4j 2
- Log4j
- JDK logging
在Mybatis中具体使用哪一个日志实现,在设置中配置
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
6.2Log4j
1.先导入Log4j的包
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2.配置文件
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/kuang.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
setting设置日志实现
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
测试类
//注意导包:org.apache.log4j.Logger
static Logger logger = Logger.getLogger(MyTest.class);
@Test
public void selectUser() {
logger.info("info:进入selectUser方法");
logger.debug("debug:进入selectUser方法");
logger.error("error: 进入selectUser方法");
SqlSession session = MybatisUtils.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> users = mapper.selectUser();
for (User user: users){
System.out.println(user);
}
session.close();
}