官方文档: MyBatis中文网
内存:断电即失
TeacherMapper接口,有一个获取所有Teacher的方法待实现
public interface TeacherMapper {
List<Teacher> getTeacherList();
}
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.7version>
dependency>
jdbc.properties
driver=com.mysql.cj.jdbc.Driver
username=root
password=root
url=jdbc:mysql:///mybatis?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC
官方配置文件模板
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<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="org/mybatis/example/BlogMapper.xml"/>
mappers>
configuration>
原本的dao接口实现类daoImpl,现在变成一个和接口同名的mapper.xml文件
TeacherMapper.xml,就是把这里面的configuration全部换成mapper
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.changGe.li.mapper.TeacherMapper">
<select id="getTeacherList" resultType="com.changGe.li.pojo.Teacher">
select * from teacher;
select>
mapper>
mybatis-config.xml
注意:文件用/号来分隔,类用.号来分隔
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="jdbc.properties">properties>
<typeAliases>
<typeAlias type="com.changGe.li.pojo.Teacher" alias="teacher"/>
typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="jdbc:mysql:///mybatis?useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/changGe/li/mapper/StudentMapper.xml"/>
<mapper resource="com/changGe/li/mapper/TeacherMapper.xml"/>
mappers>
configuration>
xml中的&要加上amp;来表示
<property name="url" value="jdbc:mysql:///mybatis?useUnicode=true&characterEncoding=utf8"/>
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;
public class MyBatisUtil {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
//读取配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-onfig.xml");
//工厂构建类 构建 得到sql会话工厂
sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//用工厂类来获取执行sql操作的对象
public static SqlSession getSqlSession(){
//打开会话,也就是开启和数据库的连接
return sqlSessionFactory.openSession();
}
}
@Test
public void test(){
//工具类获取SqlSession对象
SqlSession sqlSession = MyBatisUtil.getSqlSession();
//底层用反射机制,获取了接口TeacherMapper的类对象
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
//接口被实现类TeacherMapper.xml实现了,调用接口就是调用实现类的方法
List<Teacher> teacherList = mapper.getTeacherList();
id:1,姓名是:秦老师
for (Teacher teacher : teacherList) {
System.out.println("id:"+teacher.getId()+",姓名是:"+teacher.getName());
}
//一定要关闭会话,免得占用资源
sqlSession.close();
}
@Test
public void test(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
//sql会话时,直接调用接口中的方法
List<Teacher> teacherList = sqlSession.selectList("com.changGe.li.mapper.TeacherMapper.getTeacherList");
//id:1,姓名是:秦老师
for (Teacher teacher : teacherList) {
System.out.println("id:"+teacher.getId()+",姓名是:"+teacher.getName());
}
sqlSession.close();
}
如果找不到对象,可能因为maven是找不到mapper.xml,用下面的代码,让maven在构建项目时把文件构建进来
<build>
<resources>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
resources>
build>
好像说mapper.xml中的中文注释也会出问题,可能是要把文件格式改成UTF-8
在后面的生命周期和作用域会讲解
就是可以让mybatis直接打到资源的一个精确名字,如com.changGe.li.pojo.Teacher
对象中的值可以直接拿来用
<select id="getTeacherByIdAndName" resultType="teacher" parameterType="map">
select * from teacher where id=#{id} and name = #{name};
select>
@Test
public void test(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
HashMap<String, String> map = new HashMap<String, String>();
map.put("id","1");
map.put("name","秦老师");
Teacher teacherByIdAndName = mapper.getTeacherByIdAndName(map);
System.out.println(teacherByIdAndName);
sqlSession.close();
}
增删改一定要提交事务sqlsession.commit();
<insert id="addTeacher" parameterType="teacher">
insert into teacher values(#{id},#{name})
insert>
@Test
public void test(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher = new Teacher(2,"李长歌");
mapper.addTeacher(teacher);
//不提交事务,不更新数据
sqlSession.commit();
sqlSession.close();
}
https://blog.csdn.net/kongkongyanan/article/details/86096657
<insert id="insertStudent">
<selectKey keyProperty="id" order="AFTER">
SELECT LAST_INSERT_ID() AS ID
selectKey>
insert into student values(#{id},#{name},#{tid})
insert>
Student student = new Student();
student.setName("张三");
student.setTid(1);
mapper.insertStudent(student);
System.out.println(student.getId());
模糊查询
select * from teacher where name like concat('%',#{name},'%');
Teacher teacher = mapper.getTeacherByName("长歌");
xml规定了所有标签的顺序,必须完全符合规定
properties,settings,
typeAliases,typeHandlers,
objectFactory,objectWrapperFactory,
reflectorFactory,plugins,
environments,databaseIdProvider,
mappers
多环境配置
<environments default="test">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
dataSource>
environment>
<environment id="test">
<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>
<properties resource="jdbc.properties">
<property name="username" value="root"/>
properties>
<dataSource type="pooled">
<property name="username" value="${username}"/>
dataSource>
<typeAliases>
<typeAlias type="com.changGe.li.pojo.Teacher" alias="teacher">typeAlias>
<package name="com.changGe.li.pojo"/>
typeAliases>
<select id="getTeacherByName" resultType="teacher">
注解设置别名
@Alias("teacher")
public class Teacher {}
但是需要在mybatis-config.xml中,配置在哪个包下扫描注解
<typeAliases>
<package name="com.changGe.li.pojo"/>
typeAliases>
基本类型加_,包装类是对应的基本类型,集合首字母小写
int 别名是 _int,Integer = int, Map = map
<select id="getTeacherByName" resultType="teacher" parameterType="_int">
可以设置如日志,缓存和懒加载
slf4j依赖
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>2.0.0-alpha4version>
dependency>
<settings>
<setting name="logImpl" value="SLF4J"/>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
settings>
当用实现类或包注册时,要求:实现类和配置文件与接口同名,且同包!
<mappers>
<mapper class="com.changGe.li.mapper.TeacherMapper"/>
<package name="com/changGe/li/mapper"/>
mappers>
如果想分离,要在resource包下创建和接口相同结构的包.
因为mybatis的resource是通过classpath来找文件的
我们可以从SqlSessionFactory中获得 SqlSession 的实例。
SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
sqlsession执行rselectOne()或者selectList()等方法,直接执行sql操作,最后结束
这种方式对使用旧版本 MyBatis 的用户来说,比较熟悉。
使用指定了语句的参数和返回值相匹配的接口(比如 BlogMapper.class)
现在代码更清晰,更加类型安全,不用担心可能出错的字符串字面值,以及强制类型转换。
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
作用就是:把数据库中返回的字段的值,映射到对象的属性上
对象中有id和age两个属性
@Data
@AllArgsConstructor
@NoArgsConstructor
@Alias("teacher")
public class Teacher {
private int id;
private String ame;
}
配置结果集映射
<resultMap id="tea" type="teacher">
<id column="id" property="id"/>
<result column="name" property="ame"/>
resultMap>
<select id="getTeacherByName" resultMap="tea" parameterType="teacher">
select * from teacher where id = #{id} and name = #{ame};
select>
执行查询
Teacher teacher1 = new Teacher(2, "李长歌");
Teacher teacher = mapper.getTeacherByName(teacher1);
写resultMap时,resultType就可以不用写了
Mybatis 通过使用内置的日志工厂提供日志功能。内置日志工厂将会把日志工作委托给下面的实现之一:
MyBatis 内置日志工厂:会基于运行时检测信息,选择日志委托实现。
它会(按上面罗列的顺序)使用第一个查找到的实现。
如果你的环境中并不存在 Log4J,你却试图调用了相应的方法,MyBatis 就会忽略这一切换请求 .
当没有找到这些实现时,将会禁用日志功能。
xml声明
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
settings>
执行结果
//读者入口
Reader entry: <?xml version="1.0" encoding="UTF-8" ?>
//检查类 com.changGe.li.mapper.StudentMapper 是否符合条件 [可分配给对象]
Checking to see if class com.changGe.li.mapper.StudentMapper matches criteria [is assignable to Object]
Checking to see if class com.changGe.li.mapper.TeacherMapper matches criteria [is assignable to Object]
//打开 JDBC 连接
Opening JDBC Connection
//创建连接 1312381159
Created connection 1312381159.
//在 JDBC 连接 [com.mysql.cj.jdbc.ConnectionImpl@4e3958e7] 上将 autocommit(自动提交) 设置为 false
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4e3958e7]
//准备中
==> Preparing: select * from teacher where id = ? and name = ?;
//参数
==> Parameters: 2(Integer), 李长歌(String)
//列
<== Columns: id, name
//行
<== Row: 2, 李长歌
//总计
<== Total: 1
//返回结果
Teacher(id=2, name=李长歌)
//在 JDBC 连接 [com.mysql.cj.jdbc.ConnectionImpl@4e3958e7] 上将自动提交重置为 true
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4e3958e7]
//关闭 JDBC 连接 [com.mysql.cj.jdbc.ConnectionImpl@4e3958e7]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4e3958e7]
//将连接 1312381159 返回到池
Returned connection 1312381159 to pool.
log4j_百度百科 (baidu.com)
使用Log4j框架的作用通俗的解释:
依赖
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
log4j.properties
#将等级为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
#日志输出级别:输出DEBUG级别及以上的日志信息
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
public class MyBatisTest {
//在当前类运行时,输出日志
private static Logger logger = Logger.getLogger(MyBatisTest.class);
@Test
public void test(){
//在debug时,输出当前为debug模式
logger.debug("当前为debug模式");
SqlSession sqlSession = MyBatisUtil.getSqlSession();
//输出一条普通信息:打印sqlSession
logger.info(sqlSession);
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher1 = new Teacher(2, "李长歌");
Teacher teacher = mapper.getTeacherByName(teacher1);
System.out.println(teacher);
sqlSession.close();
try {}catch (Exception e){}
finally {
logger.error("报错了");
}
}
}
日志文件的存放地址
部分日志信息
<select id="getStudent" resultType="student">
select * from student;
select>
@Test
public void test(){
SqlSession sqlSession = MyBatisUtil.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//分页,从3开始显示,显示4个
RowBounds rowBounds = new RowBounds(2, 4);
//方法路径,参数和分页
List<Student> students = sqlSession.selectList("com.changGe.li.mapper.StudentMapper.getStudent", null, rowBounds);
for (com.changGe.li.pojo.Student student : students) {
System.out.println(student);
}
sqlSession.close();
}
MyBatis的分页插件:PageHelper: MyBatis 分页插件 PageHelper
根本目的为了解耦
@Select("select * from student;")
List<Student> getStudent();
Mapper中有一个sqlSession,里面保存了所有的配置信息
TeacherMapper
@Insert("insert into teacher values(#{id},#{name});")
/**
* 将传参id的值交给@Param中的id,然后赋值给sql语句中的#{id}
*
* @Param中的参数名必须与#{}一致,mybatis就是从这里取值的
*/
int insertTeacher(@Param("id")int id,@Param("name")String name);
//设置开启自动提交
return sqlSessionFactory.openSession(true);
注解里的需要的参数,会自动去方法传参中找.
比如传参是对象,就会去自动匹配对象的字段。
@Insert("insert into teacher values(#{id},#{name});")
/**
* 注解里的需要的参数,会自动去方法传参中找.
*/
int insertTeacher(Teacher teacher);
mapper.insertTeacher(new Teacher(4,"太平公主"));
MyBatis运行流程(源码):https://zhuanlan.zhihu.com/p/67738448
简略易读版本: MyBatis的执行流程详解 - 知乎 (zhihu.com)
Resource类读取配置文件,创建SqlSessionFactroyBuilder对象
//读取配置文件的流
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//sql会话工厂构建类 构建 得到sql会话工厂
sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
这个对象底层用流,创建了一个XMLConfig对象.
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//通过流读取properties文件,创建XMLConfigBUiler对象
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//XMLConfig对象读取xml配置文件
//解析文件中数据,返回SqlSessionFactory对象
return build(parser.parse());
} catch (Exception e) {} finally {
ErrorContext.instance().reset();
}
}
XMLConfigBUiler对象读取xml配置文件,创建Configuration对象,这个对象中包含了所有的基本配置信息
sqlSession中包含了configuration,里面有所有的配置信息,如environment(环境)
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
SqlSessionFactroy工厂对象,构建SqlSession对象(openSession)时,底层创建Transactional事务管理器–监听事务.同时创建Execetor执行器
sqlSession中包含executor和transaction对象
return sqlSessionFactory.openSession();
SqlSessionFactory的实现类:DefaultSqlSessionFactory
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
//新建事务管理器
Transaction tx = null;
try {
//获取环境
final Environment environment = configuration.getEnvironment();
//从环境中获取:事务管理器工厂
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//事务管理器赋值:所有的环境数据,等级和是否自动提交
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//创建执行器,专门用来执行sql操作,和缓存等
final Executor executor = configuration.newExecutor(tx, execType);
//把事务管理器和执行器都返回
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
//关闭事务管理器
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
}
}
它是一个插件,还需要maven依赖(也可以直接引用依赖)
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.22version>
dependency>
@Data @AllArgsConstractor @NoArgsConstractor
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private int id;
private String name;
private int tid;
}
有一种说法是lombok改变了java的源码,让java语言出现了"文明断层"的情况