笔记跟随视频学习总结而成。
CREATE DATABASE `mybatis`;
USE `mybatis`;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(20) NOT NULL,
`name` varchar(30) DEFAULT NULL,
`pwd` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `user`(`id`,`name`,`pwd`) values (1,'halo','123456'),(2,'whot','abcdef'),(3,'学习MyBatis','987654');
父工程导包
<dependencies>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.25version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.7version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
dependencies>
子工程中,在resources文件夹下创建 mybatis-config.xml 文件:
这是MyBatis核心配置文件
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="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimeZone=UTC"/>
<property name="username" value="halo"/>
<property name="password" value="hutonghao"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/whot/dao/UserMapper.xml"/>
mappers>
configuration>
编写MyBatis工具类
package com.whot.util;
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 MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
//使用MyBatis第一步: 获取sqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream =Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//获取SqlSession连接
//有了sqlSessionFactory,就从中获取SQLSession的实例
//SQLSession 中完全包含了面向数据库执行的SQL命令所需的所有方法
public static SqlSession getSession(){
return sqlSessionFactory.openSession();
}
}
编写实体类
package com.whot.pojo;
import lombok.Data;
@Data
public class User {
private int id;
private String name;
private String pwd;
}
编写Mapper接口类
package com.whot.dao;
import com.whot.pojo.User;
import java.util.List;
public interface UserMapper {
List<User> selectUser();
}
编写Mapper.xml配置文件
特别注意:namespace的路径唯一绑定对应接口,id对应接口中的方法名
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.whot.dao.UserMapper">
<select id="selectUser" resultType="com.whot.pojo.User">
select * from user
select>
mapper>
junit测试:
package com.whot.dao;
import com.whot.pojo.User;
import com.whot.util.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class MyTest {
@Test
public void selectUser() {
SqlSession session = MybatisUtils.getSession();
//方法一:
List<User> users = session.selectList("com.whot.dao.UserMapper.selectUser");
//方法二: 不推荐
// UserMapper mapper = session.getMapper(UserMapper.class);
// List users = mapper.selectUser();
for (User user: users){
System.out.println(user);
}
session.close();
}
}
报错信息:
org.apache.ibatis.binding.BindingException: Type interface com.kuang.dao.UserDao is not known to the MapperRegistry.
解决方法:
在mybatis-config.xml 文件,加入:
<mappers> <mapper resource="com/whot/dao/UserMapper.xml"/> mappers>
报错信息:could not find resources ~~~.xml
原因:
maven 由于他的约定大于配置 , 之后可以能遇到我们写的配置文件 , 无法被导出或者生效的问题
解决方法:
在父工程中,或者子工程中,后者两者的pom文件中加入:
<build> <resources> <resource> <directory>src/main/javadirectory> <includes> <include>**/*.propertiesinclude> <include>**/*.xmlinclude> includes> <filtering>falsefiltering> resource> <resource> <directory>src/main/resourcesdirectory> <includes> <include>**/*.propertiesinclude> <include>**/*.xmlinclude> includes> <filtering>falsefiltering> resource> resources> build>
增删改查操作,原理大同小异,大致总结流程:
小结:
关于模糊查询
第1种:在Java代码中添加sql通配符。
String wildcardname = “%smi%”;List<name> names = mapper.selectlike(wildcardname);<select id=”selectlike”> select * from foo where bar like #{value}</select>
第2种:在sql语句中拼接通配符,会引起sql注入
string wildcardname = “smi”;list names = mapper.selectlike(wildcardname);
configuration(配置) properties(属性) settings(设置) typeAliases(类型别名) typeHandlers(类型处理器) objectFactory(对象工厂) plugins(插件) environments(环境配置) environment(环境变量) transactionManager(事务管理器) dataSource(数据源) databaseIdProvider(数据库厂商标识) mappers(映射器)<!-- 注意元素节点的顺序!顺序不对会报错 -->
<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指定)
不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
子元素节点:environment
<transactionManager type="[ JDBC | MANAGED ]"/>
子元素节点:dataSource(数据源)
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
数据源是必须配置的。
有三种内建的数据源类型
type="[UNPOOLED|POOLED|JNDI]")
unpooled: 这个数据源的实现只是每次被请求时打开和关闭连接。
pooled: 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来 , 这是一种使得并发 Web 应用快速响应请求的流行处理方式。
jndi:这个数据源的实现是为了能在如 Spring 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。
数据源也有很多第三方的实现,比如dbcp,c3p0,druid等等….
数据库这些属性都是可外部配置且可动态替换的,既可以在典型的 Java 属性文件中配置,亦可通过 properties 元素的子元素来传递。具体的官方文档
优化配置文件:
第一步 : 在资源目录下新建一个db.properties文件
driver=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8username=rootpassword=123456
第二步 : 将文件导入properties 配置文件
配置文件优先级问题: 外部引用优于内部
如果内部定义 与 外部引用中有同一个字段,优先使用外部的配置文件!
为java类型设置一个短的名字,减少类完全限定名的冗余 在写sql语句的resultType时可简写
<typeAliases> <typeAlias type="com.whot.pojo.User" alias="halo"/>typeAliases>
也可以指定包名,对包下搜索需要的java Bean,扫到的类 取别名 为 首字母小写(com.pojo.User 别名 为user)
<typeAliases> <package name="com.whot.pojo"/>typeAliases>
当实体类较少时,用第一种; 当实体类非常多时,建议使用第二种
理解我们目前已经讨论过的不同作用域和生命周期类是至关重要的
因为错误的使用会导致非常严重的并发问题
作用域理解
SqlSessionFactoryBuilder 的作用在于创建 SqlSessionFactory,创建成功后,SqlSessionFactoryBuilder 就失去了作用,所以它只能存在于创建 SqlSessionFactory 的方法中,而不要让其长期存在。因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
SqlSessionFactory 可以被认为是一个数据库连接池,它的作用是创建 SqlSession 接口对象。因为 MyBatis 的本质就是 Java 对数据库的操作,所以 SqlSessionFactory 的生命周期存在于整个 MyBatis 的应用之中,所以一旦创建了 SqlSessionFactory,就要长期保存它,直至不再使用 MyBatis 应用,所以可以认为 SqlSessionFactory 的生命周期就等同于 MyBatis 的应用周期。
SqlSessionFactory一旦被创建就应该在应用的运行期间一直存在 , 没有任何理由丢弃它或重新创建
另一个实例
由于 SqlSessionFactory 是一个对数据库的连接池,所以它占据着数据库的连接资源。如果创建多个 SqlSessionFactory,那么就存在多个数据库连接池,这样不利于对数据库资源的控制,也会导致数据库连接资源被消耗光,出现系统宕机等情况,所以尽量避免发生这样的情况。
因此在一般的应用中我们往往希望 SqlSessionFactory 作为一个单例,让它在应用中被共享。所以说 SqlSessionFactory 的最佳作用域是应用作用域。
如果说 SqlSessionFactory 相当于数据库连接池,那么 SqlSession 就相当于一个数据库连接(Connection 对象),你可以在一个事务里面执行多条 SQL,然后通过它的 commit、rollback 等方法,提交或者回滚事务。所以它应该存活在一个业务请求中,处理完整个请求后,应该关闭这条连接,让它归还给 SqlSessionFactory,否则数据库资源就很快被耗费精光,系统就会瘫痪,所以用 try…catch…finally… 语句来保证其正确关闭。
所以 SqlSession 的最佳的作用域是请求或方法作用域。
resultMap
元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets
数据提取代码中解放出来。resultMap
能够代替实现同等功能的长达数千行的代码。你已经见过简单映射语句的示例了,但并没有显式指定 resultMap
。比如:
<select id="selectUserById" resultType="map"> select id , name , pwd from user where id = #{id}select>
上述语句只是简单地将所有的列映射到 HashMap
的键上,这由 resultType
属性指定。虽然在大部分情况下都够用,但是 HashMap 不是一个很好的模型。你的程序更可能会使用 JavaBean 或 POJO(Plain Old Java Objects,普通老式 Java 对象)作为模型。
ResultMap
最优秀的地方在于,虽然你已经对它相当了解了,但是根本就不需要显式地用到他们。
返回值类型为resultMap
<select id="selectUserById" resultMap="UserMap"> select id , name , pwd from user where id = #{id}select>
编写resultMap,实现手动映射!
<resultMap id="UserMap" type="User"> <id column="id" property="id"/> <result column="name" property="name"/> <result column="pwd" property="password"/>resultMap>
如果世界总是这么简单就好了。但是肯定不是的,数据库中,存在一对多,多对一的情况,我们之后会使用到一些高级的结果集映射,association,collection这些概念需要进一步学习!
<settings> <setting name="logImpl" value="STDOUT_LOGGING"/>settings>
简介:
使用步骤:
导入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.ConsoleAppenderlog4j.appender.console.Target = System.outlog4j.appender.console.Threshold=DEBUGlog4j.appender.console.layout = org.apache.log4j.PatternLayoutlog4j.appender.console.layout.ConversionPattern=[%c]-%m%n#文件输出的相关设置log4j.appender.file = org.apache.log4j.RollingFileAppenderlog4j.appender.file.File=./log/kuang.loglog4j.appender.file.MaxFileSize=10mblog4j.appender.file.Threshold=DEBUGlog4j.appender.file.layout=org.apache.log4j.PatternLayoutlog4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n#日志输出级别log4j.logger.org.mybatis=DEBUGlog4j.logger.java.sql=DEBUGlog4j.logger.java.sql.Statement=DEBUGlog4j.logger.java.sql.ResultSet=DEBUGlog4j.logger.java.sql.PreparedStatement=DEBUG
setting设置日志实现
<settings> <setting name="logImpl" value="LOG4J"/>settings>
在程序中使用Log4j进行输出!
//注意导包:org.apache.log4j.Loggerstatic Logger logger = Logger.getLogger(MyTest.class);@Testpublic 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 users = mapper.selectUser(); for (User user: users){ System.out.println(user); } session.close();}
感觉使用MyBatis-Plus更为简单,暂时跳过。
什么是动态SQL:根据不同条件,生成不同的sql语句
<select id="queryBlogIf" parameterType="map" resultType="blog"> select * from blog where 1 = 1 <if test="title != null"> and title = #{title} if> <if test="author != null"> and author = #{author} if>select>
<select id="queryBlogIf" parameterType="map" resultType="blog"> select * from blog <where> <if test="title != null"> title = #{title} if> <if test="author != null"> and author = #{author} if> where>select>
这个“where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以AND 或OR 开头的,则它会剔除掉。 【自动添加where,自动去除或添加 and、or】
<where> <choose> <when test="title ! = null"> title = #{title} when> <when test=" author ! = null"> and author = # { author} when > <otherwise> and views = #{views} otherwise> choose>where>
解读一下上面的代码:
choose标签,作用:从中选择一个条件成立的 拼接sql 从前往后,成立就退出
otherwise标签,放于choose中,作用:当choose中没有成立的,就选otherwise中的进行拼接
<update id="updateBlog" parameterType="map"> update blog <set> <if test="title != null"> title = #{title}, if> <if test="author != null"> author = #{author} if> set> where id = #{id};update>
功能和用法都与 where 类似
set元素会动态前置 SET 关键字, 同时也会删除无关的逗号
<select id="queryBlogForeach" parameterType="map" resultType="blog"> select * from blog <where> <foreach collection="ids" item="id" open="and (" close=")" separator="or"> id=#{id} foreach> where>select>