Mybatis是一个持久层框架,要细致的说是一个版持久性的框架,通过简单的xml或者注解进行配置,使得数据库的操没有那么繁琐;
mybatis
mybatis是一种挂逆行型映射框架,用于解决数据库操做时遇到的一些问题;
在学习mybatis时还接触到了一个全表映射的框架 hibernate也是用于数据库操做的一个框架,hibernate不要求熟练掌握sql,而是根据对应逻辑来动态生成sql,所以开发效率要高于mybatis,但是随着数据库中内容的增多以及多张表的存在,在进行多表关联查询时性能会比mybatis低,所以herbernate适用于不太复杂,且对性能要求不高的项目中;
简单的案例----数据库CURD
mybatis并不依赖于spring,只是他们通常一起使用,在实际开发中我们经常会遇到查询的功能,如果是通过jdbc进行开发,则代码量会很大,同时如果要修改查询的则要去修改整个程序的代码,非常不方便;
查询用户
在实际开发中,查询操作通常都会涉及单条数据的精确查询以及多条数据的模糊查询。
第一步------>>>新建一个maven工程
引入相应依赖—
lombok
mybatis
junit
mysql-connector
log4j
下面是依赖的代码,可以直接拿走
<dependencies>
<!-- 自动资源管理,自动生成getters,setters,equals,hashCode和toString-->
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
<!--测试Junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
然后开始写代码了去实现想要的功能;
这里以图书商店的后台数据库为例
还需要准备一个数据表----->>>
DROP TABLE IF EXISTS `bookstore`;
CREATE TABLE `bookstore` (
`BookId` int NOT NULL,
`BookName` varchar(255) DEFAULT NULL,
`BookPublish` varchar(255) DEFAULT NULL,
`BookPrice` double(10,2) DEFAULT NULL,
`BookKind` varchar(16) DEFAULT NULL,
`BookCount` int DEFAULT NULL,
PRIMARY KEY (`BookId`),
KEY `name_index` (`BookName`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
insert into `bookstore`(`BookId`,`BookName`,`BookPublish`,`BookPrice`,`BookKind`,`BookCount`) values
(1001,'java入门','清华出版社',56.80,'计算机',70),
(1002,'python深入','机械工业出版社',78.60,'计算机',130),
(1003,'前端html','清华出版社',88.80,'计算机',100),
(1004,'废都','张江出版社',25.70,'文学名著',100),
(1005,'官场现形记','青岛出版社',23.80,'文学名著',100),
(1006,'红楼梦','青岛出版社',36.80,'文学名著',100),
(1007,'母猪的产后护理','机械工业出版社',27.80,'实用技术',100),
(1008,'车辆维修大全','机械工业出版社',26.80,'实用技术',100),
(1009,'如何讨取富婆欢心富婆','开心出版社',125.00,'生活技能',100),
(1010,'JVM调优','北京科技出版社',68.90,'计算机',120),
(1011,'GO','南京邮电出版社',78.90,'计算机',120),
(1012,'Android入门','电子科技出版社',88.90,'计算机',120),
(1014,'果树种植学','西北农林出版社',128.90,'农业',120),
(1015,'笑话','上海出版社',48.90,'生活',120),
(1111,'MQ消息队列','北大出版社',98.90,'计算机',120);
第二步------->>>编写代码去实现功能
写一个实体类
看起来数据表中的字段有点多,别怕,前面不是引入了lombok吗,就是简化代码量的;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book implements Serializable {
private Integer BookId;
private String BookName;
private String BookPublish;
private Double BookPrice;
private String BookKind;
private Integer BookCount;
}
是不是很简洁,set/get方法,toString,hashcode等通过lombok的注解去实现而不用,如果你在使用过程中遇到了错误,那么可能你还没有开启lombok插件使其自动生效
开启方式---->>>
第三步----->>>在resources文件夹下建立
mybatis全局配置文件mybatis-config.xml
在这之前还需要配置一个jdbc配置文件,当然你也可以直接将数据库连接要素写在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>
<properties resource="jdbc.properties"/>
<settings>
<!--指定mybatis日志方式,如果不指定,自动查找处理-->
<setting name="logImpl" value="LOG4J"/>
</settings>
<typeAliases>
<!--包扫描起别名 类的短路径名首字母小写-->
<package name="com.gavin.pojo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc_driver}"/>
<property name="url" value="${jdbc_url}"/>
<property name="username" value="${jdbc_username}"/>
<property name="password" value="${jdbc_password}"/>
</dataSource>
</environment>
</environments>
<!--加载mapper映射文件-->
<mappers>
<mapper resource="com.gavin.mapper/BookMapper.xml"/>
</mappers>
</configuration>
jdbc.properties
jdbc_driver=com.mysql.cj.jdbc.Driver
jdbc_url=jdbc:mysql://127.0.0.1:3306/gavin?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
jdbc_username=gavin
jdbc_password=955945
如果想要打印日志还需要借助log4j或者log4j2,本次以log4j为例子
在resources文件夹下建立log配置文件
log4j.properties
log4j.rootLogger=info,stdout,logfile
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=d:/gavin.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %F %p %m%n
最后编写测试类----->
这里要理解mybatis的工作流程才能更好的编写测试类—>>>
首先mybatis共工作时必备两个文件-------mybatis-config.xml(全局配置文件)和Mapper.xml(映射文件)当然文件名不一定非得是这个
mybatis正是通过这两个文件来解析并创建会话的;
每次会话都会创建一次sqlsessionFactory对象,然后通过工厂对象创建sqlsession对象,sqlsession对象用于接收请求,然后分析要执行哪些sql语句,最后传给executor去执行,执行的时候会用到statementHandler去对接数据库;
这就是mybatis的基本工作原理;
看图----->>
然后开始写测试代码,通过测试模块来完成测试的编写;
public class Test1 {
private SqlSession sqlSession =null;
@Before
public void init(){
InputStream resource =null;
//载入配置文件
try {
resource= Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resource);
sqlSession= build.openSession(true);
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void test(){
List<Book> list = sqlSession.selectList("findAll");
list.stream().forEach(System.out::println);
}
@After
public void testClose(){
sqlSession.close();
}
}
运行结果---->>>
有时候我们 会遇到一些错误,不要着急,要细心查看日志,看是哪里出错了;
增删查改其实答题原理是一样,都要注意mapper的路径问题;
好了接下来开始了解各个配置文件中的书写格式le
Mapper文件
全局配置文件
mybatisconfig.xml
实行模糊查询
修改sql语句就可以了
但是这样写无法防止sql注入,
查看有没有合适的方法预编译的,然而并没有,那只能通过字符串的拼接了,
就像这样
添加数据
基本操做不变,就是sql语句和数据库操做的方法会有变动;
注意这次是插入数据,就不用写返回值了,因为insert标签下也没有resultType属性
如果没去掉图片横线处的内容,会报错误,
我也不知道为啥明明注释掉了,然后才发现少了一些东西…很奇怪,错误总在不经意间出现;
更新数据
删除数据
这样mybatis对于数据库的增删查改就结束了;
来做一个小小的总结-----------------<>>>
由以上操做基本也可以看出,mybatis的操做大致可以分为6步;
1,读取配置文件 -----mybatisconfig.xml与Mapper.xml
2加载配置文件并根据配置文件创建sqlsessionFactory
3,根据sqlsessionFactory创建SqlSession
4,由SqlSession负责联系数据库
5,关闭SqlSession
虽然表面上是SqlSession负责连接数据库,其实底层是由excutor和statemenHandler实现的
熟悉了工作流程之后需要深入学习一下
MyBatis的核心对象------->>>
SqlSessionFactory
SqlSessionFactory是单个数据库映射关系经过编译后的内存镜像,通过SqlSessionFactoryBuilder对象来构建,而SqlSessionFactory的实例由mybatis全局配置文件构建
所以
代码就可以写下来了,通过流来读取全局配置文件
Resources的getResourceAsStream方法来读取配置文件,然后通过SqlSessionFactoryBuilder的build来构建一个SqlSessionFactory对象;
SqlSessionFactory对象是线程安全的,一旦被创建,在整个应用执行期间都会存在。如果多次创建同一个数据库的SqlSessionFactory,那么此数据库的资源将很容易被耗尽。所以在构建SqlSessionFactory实例时,建议使用单列模式,即只实例化一次
SqlSession
sqlsession中封装了JDBC连接,是应用与数据库之间执行交互的一个单线程对象;
SqlSession实例是不能被共享的,也是线程不安全的,因此其使用范围最好限定在一次请求或一个方法中,绝不能将其放在一个类的静态字段、实例字段或任何类型的管理范围中使用。使用完SqlSession对象之后,要及时将它关闭,通常可以将其放在finally块中关闭。
sqlsession中的常用方法
<T> T selectOne(String statement);
//该方法返回执行SQL语句查询结果的一个泛型对象。
<T> T selectOne(String statement, Object parameter);
//该方法返回执行SQL语句查询结果的一个泛型对象。
<E> List<E> selectList(String statement, Object parameter);
//该方法返回执行SQL语句查询结果的泛型对象的集合。
<E> List<E> selectList(String statement, Object parameter);
//该方法返回执行SQL语句查询结果的泛型对象的集合。
<E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);
//rowBounds是用于分页的参数对象。该方法返回执行SQL语句查询结果的泛型对象的集合。
void select(String statement, Object parameter, ResultHandlerhandler);
//ResultHandler对象用于处理查询返回的复杂结果集,通常用于多表查询。
//还有insert,update,delete,commit以及rollback就不在此显示了
MyBatis配置文件
mybatis配置属性顺序
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
<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>
mapper配置文件
错误演示----->>>
在说一下在mybatis中的全局配置文件中的一些小细节
比如上面案例开发中引入了一个外部配置文件jdbc.properties用于变量的一个引入,其实还有另一种操做,跟他很类似,但是不用在另外配置一个文件了;
那我们可以在mybatis配置文件中直接引入一个全局变量------->>
一般开发者能够还是习惯将四要素放在文件(jdbc.properties)外以尽可能降低耦合度;
但是这样就会来一个问题,如果两种方式都配置了,那么是按照谁来走呢?
实际测试后 发现是按照外部配置的走的,原因是
myabatis在读取配置时是
先读取内部的properties中的内容,
然后在读取外部resource引入的,如果同名了,
则读取的外部resource的值会覆盖掉内部读取的值;
所以临时修改数据库额连接时只要不同名就可以了;
如果一个属性在不只一个地方进行了配置,那么,MyBatis 将按照下面的顺序来加载:
首先读取在 properties 元素体内指定的属性。 然后根据 properties 元素中的 resource
属性读取类路径下属性文件,或根据 url 属性指定的路径读取属性文件,并覆盖之前读取过的同名属性。
最后读取作为方法参数传递的属性,并覆盖之前读取过的同名属性。 因此,通过方法参数传递的属性具有最高优先级,resource/url
属性中指定的配置文件次之,最低优先级的则是 properties 元素中指定的属性。
同时我们在代码中也可以指定实际要用到的数据库环境----->>
设置默认值
从 MyBatis 3.4.2 开始,你可以为占位符指定一个默认值。
在配置文件中启动默认值这种时候我们可以为某一个配置设置默认值----
<property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/>
比如我们在jdbc配置文件中只设置了三个值------>>
如果你在属性名中使用了 “:” 字符(如:db:username),或者在 SQL 映射中使用了 OGNL 表达式的三元运算符(如: ${tableName != null ? tableName : ‘global_constants’}),就需要设置特定的属性来修改分隔属性名和默认值的字符。例如:
<properties resource="org/mybatis/example/config.properties">
<!-- ... -->
<property name="org.apache.ibatis.parsing.PropertyParser.default-value-separator" value="?:"/> <!-- 修改默认值的分隔符 -->
</properties>
<dataSource type="POOLED">
<!-- ... -->
<property name="username" value="${db:username?:ut_user}"/>
</dataSource>
# {} 与${}的区别
在编译ssql语句时我们常常会用到一些参数什么的,在编译时传统jdbc操作时我们习惯于用预编译的方式;
如果不用预编译的方式很可能发生sql注入,所以 # {} 与${}的区别 其实就是预编译和不预编译的区别,下面给一个案例-----
设置自增----->
可以单独配置,也可以在全局配置中进行配置;