- 注意点 有坑
- 相关博文
- 1. MyBatis使用
- 2. mybatis参数传递
- 简介:什么是MyBatis?
- 入门
- 安装
- 从 XML 中构建 SqlSessionFactory
- 不使用 XML 构建 SqlSessionFactory
- 从 SqlSessionFactory 中获取 SqlSession
- 第一个MyBatis程序
- 命名空间:
- 作用域(Scope)和生命周期
- XML配置
- 属性(properties)
- 设置(settings)
- 日志 logilpl
- STDOUT_LOGGING (Mybatis-04)
- Log4j (Mybatis-04)
- 类型别名(typeAliases)
- 环境配置(environments)
- 事务管理器 (transactionManager)
- datasource 数据源 (连接数据库)
- UNPOOLED POOLED
- 映射器(mappers)(有一个小坑)
- 其他配置
- XML 映射器
- 参数
- 使用map传递参数
- 字符串替换
- 结果映射 resultmap (解决数据库中的字段名和实体类中的属性名不匹配)
- 高级结果映射 (重点是一对多和多对一)
- 缓存
- 动态SQL
- 思考
- 模糊查询怎么写?
- mybatis怎样防止sql注入
- 什么是SQL注入
- Mybatis如何防止SQL注入
- 弃用$可以吗
- 解决属性名和字段名不一致的问题
- 为什么不一致会出现问题
- 动态sql
- 日志工厂
- 分页实现
- 使用limit
- 使用RowBounds
1.mybatis 默认开启事务,如果进行了增,删,改等操作,需要手动提交事务。
2. 在和spring整合之后,就不再需要手动处理事务了。
MyBatis使用
2. mybatis参数传递mybatis传递参数的方法;
简介:什么是MyBatis?- MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。
- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
- MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
源码可以在github上看到。。。
入门 安装从 XML 中构建 SqlSessionFactoryorg.mybatis mybatis x.x.x
这里一般被放在一个工具类中。 详见Mybatis-01
String resource = "org/mybatis/example/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
mybatis-config.xml:
不使用 XML 构建 SqlSessionFactory
DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
从 SqlSessionFactory 中获取 SqlSession
之前的
try (SqlSession session = sqlSessionFactory.openSession()) {
Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
}
但现在有了一种更简洁的方式——使用和指定语句的参数和返回值相匹配的接口(比如 BlogMapper.class),现在你的代码不仅更清晰,更加类型安全,还不用担心可能出错的字符串字面值以及强制类型转换。
try (SqlSession session = sqlSessionFactory.openSession()) {
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
}
第一个MyBatis程序
命名空间:
即 mapper对应的mapper.xml中的 namespace,用来绑定接口和对应的xml配置文件。。。。
作用域(Scope)和生命周期提示:
依赖注入框架可以创建线程安全的、基于事务的 SqlSession 和映射器,并将它们直接注入到你的 bean 中,因此可以直接忽略它们的生命周期。
SqlSessionFactoryBuilder
这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。
解释:一旦创建之后就不再需要了
局不变量
SqlSessionFactory
SqlSessionFactory ==一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 ==
使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。
因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
解释:
- 可以想象为:数据库连接池
- SqlSessionFactory一旦被创建就应该在应用运行前进一直存在,没有任何理由丢弃它或重新创建另一个实例。
- 因此SqSessionFactory的最佳作用域是应用作用域
- 最简单的就是使用单例模式或者静态单例模式。。。
SqlSession
每个线程都应该有它自己的 SqlSession 实例。
SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,==每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 ==
解释:
- 连接到池的一个请求!
- SqlSession的实例不是线程安全的,因此是不能被共享的,所以最佳的所用于是请求或方法作用域
- 用完之后需要立即关闭
这里的每一个Mapper都代表了一个业务。
XML配置针对的就是mybatis-config.xml中的配置。
mybatis-config.xml 中的各项配置的顺序必须如上图所示,否则会报错。。。
我们可以通过properties属性来实现引用配置文件。
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。例如:
driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306useSSL=true&useUnicode=true&characterEncoding=UTF-8 username=root password=123456
注意:
如果一个属性在不只一个地方进行了配置,那么,MyBatis 将按照下面的顺序来加载:
1.首先读取在 properties 元素体内指定的属性。
2.然后根据 properties 元素中的 resource 属性读取类路径下属性文件,或根据 url 属性指定的路径读取属性文件,并覆盖之前读取过的同名属性。
3.最后读取作为方法参数传递的属性,并覆盖之前读取过的同名属性。
因此,通过方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的则是 properties 元素中指定的属性。
设置(settings)MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 比如日志相关设置就在里面。。。
例如:懒加载,缓存,驼峰命名自动映射
日志 logilpl指定Mybatis日志的具体实现,未指定时将自动查找。
STDOUT_LOGGING 掌握
SLF4J
LOG4J 掌握
LOG4J2
JDK_LOGGING
COMMONS_LOGGING
NO_LOGGING
标准日志输出,不需要配置,即可实现。
Log4j (Mybatis-04)简介:
- Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,
使用:
- 先导入包
log4j log4j 1.2.17
- log4j.properties
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/zhx.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
类型别名(typeAliases)
1.类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:
当这样配置时,Blog 可以用在任何使用 domain.blog.Blog 的地方。
2.也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author;
3.若有注解,则别名为其注解值。见下面的例子:
@Alias("author")
public class Author {
...
}
环境配置(environments)
注意:同一个xml文件中,可以配置多个environment
MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。还有许多类似的使用场景。
不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
所以,如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。而如果是三个数据库,就需要三个实例,依此类推,记起来很简单:
每个数据库对应一个 SqlSessionFactory 实例
为了指定创建哪种环境,只要将它作为可选的参数传递给 SqlSessionFactoryBuilder 即可。可以接受环境配置的两个方法签名是:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);
如果忽略了环境参数,那么将会加载默认环境,如下所示:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, properties);
environments 元素定义了如何配置环境:
提示: 如果你正在使用 Spring + MyBatis,则没有必要配置事务管理器,因为 Spring 模块会使用自带的管理器来覆盖前面的配置。
事务管理器 (transactionManager)在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):
- JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
- MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。例如:
datasource 数据源 (连接数据库)
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
常用的数据源:dbcp,c3p0,druid
有三种内建的数据源类型(也就是 type=[UNPOOLED|POOLED|JNDI]"):
UNPOOLED POOLED 映射器(mappers)(有一个小坑)作用:告诉MyBatis在哪里找到SQL映射语句。
注意点:1.接口和他的mapper配置文件必须同名!
2.接口和他的mapper配置文件必须在同一个包下。。。
这些配置会告诉 MyBatis 去哪里找映射文件。。。。。。
// 已经废弃
其他配置
plugins 插件
mybatis-generator-core
mybatis-plus
通用吗 mapper
cache – 该命名空间的缓存配置。
cache-ref – 引用其它命名空间的缓存配置。
resultMap – 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。
parameterMap – 老式风格的参数映射。此元素已被废弃,并可能在将来被移除!请使用行内参数映射。文档中不会介绍此元素。
sql – 可被其它语句引用的可重用语句块。
insert – 映射插入语句。
update – 映射更新语句。
delete – 映射删除语句。
select – 映射查询语句。
mybatis传递参数
之前见到的所有语句都使用了简单的参数形式。但实际上,参数是 MyBatis 非常强大的元素。对于大多数简单的使用场景,你都不需要使用复杂的参数,不需要指定 paramType比如:
上面的这个示例说明了一个非常简单的命名参数映射。鉴于参数类型(parameterType)会被自动设置为 int,这个参数可以随意命名。原始类型或简单数据类型(比如 Integer 和 String)因为没有其它属性,会用它们的值来作为参数。 然而,如果传入一个复杂的对象,行为就会有点不一样了。比如:
insert into users (id, username, password) values (#{id}, #{username}, #{password})
如果 User 类型的参数对象传递到了语句中,会查找 id、username 和 password 属性,然后将它们的值传入预处理语句的参数中。
使用map传递参数假设,实体类,或者数据库中的表,字段或参数过多,我们应当考虑使用map!
int addUser1(Mapmap);
insert into mybatis.user(id, name, pwd) VALUES (#{userId},#{userName},#{passWord})
@Test
public void addUser1(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
HashMap map = new HashMap<>();
map.put("userId",7);
map.put("userName","十yi号");
map.put("passWord","123412342135");
userMapper.addUser1(map);
//提交事务
sqlSession.commit();//很重要
sqlSession.close();
}
字符串替换
默认情况下,使用 #{} 参数语法时,MyBatis 会创建 PreparedStatement 参数占位符,并通过占位符安全地设置参数(就像使用 ? 一样)。 这样做更安全,更迅速,通常也是首选做法,不过有时你就是想直接在 SQL 语句中直接插入一个不转义的字符串。 比如 ORDER BY 子句,这时候你可以:
ORDER BY ${columnName}
结果映射 resultmap (解决数据库中的字段名和实体类中的属性名不匹配)
没有显式指定 resultMap。比如:
上述语句只是简单地将所有的列映射到 HashMap 的键上,这由 resultType 属性指定。虽然在大部分情况下都够用,但是 HashMap 并不是一个很好的领域模型。你的程序更可能会使用 JavaBean 或 POJO(Plain Old Java Objects,普通老式 Java 对象)作为领域模型。MyBatis 对两者都提供了支持。看看下面这个 JavaBean:
package com.someapp.model;
public class User {
private int id;
private String username;
private String hashedPassword;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getHashedPassword() {
return hashedPassword;
}
public void setHashedPassword(String hashedPassword) {
this.hashedPassword = hashedPassword;
}
}
基于 JavaBean 的规范,上面这个类有 3 个属性:id,username 和 hashedPassword。这些属性会对应到 select 语句中的列名。
在这些情况下,MyBatis 会在幕后自动创建一个 ResultMap,再根据属性名来映射列到 JavaBean 的属性上。如果列名和属性名不能匹配上,可以在 SELECT 语句中设置列别名(这是一个基本的 SQL 特性)来完成匹配。比如:
方法1:
方法2:
你会发现上面的例子没有一个需要显式配置 ResultMap,这里显示配置ResultMap
注意:可以只需要配置不匹配的字段即可,匹配的不用管。。。
然后在引用它的语句中设置 resultMap 属性就行了(注意我们去掉了 resultType 属性)。比如:
高级结果映射 (重点是一对多和多对一) 缓存 动态SQL 思考 模糊查询怎么写?1.java代码执行的时候,传递通配符
@Test
public void getUserLike(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//模糊查询
List list = userMapper.getUserLike("%张%");
for (User user : list) {
System.out.println(user);
}
sqlSession.close();
}
- 在sql拼接中使用通配符
Mybatis这个框架在日常开发中用的很多,比如面试中经常有一个问题:$和#的区别,它们的区别是使用#可以防止SQL注入,今天就来看一下它是如何实现SQL注入的
什么是SQL注入在讨论怎么实现之前,首先了解一下什么是SQL注入,我们有一个简单的查询操作:根据id查询一个用户信息。
它的sql语句应该是这样:select * from user where id = 。
我们根据传入条件填入id进行查询。
如果正常操作,传入一个正常的id,比如说2,那么这条语句变成
select * from user where id =2。
这条语句是可以正常运行并且符合我们预期的。
但是如果传入的参数变成’’ or 1=1,这时这条语句变成select * from user where id = ‘’ or 1=1。
让我们想一下这条语句的执行结果会是怎么?
它会将我们用户表中所有的数据查询出来,显然这是一个大的错误。这就是SQL注入。
在开头讲过,可以使用 # 来防止SQL注入,它的写法如下:
SELECt * FROM user where id = #{id} 在mybatis中查询还有一个写法是使用$,它的写法如下:
select * from user where id = ${id}
当我们在外部对这两个方法继续调用时,发现如果传入安全的参数时,两者结果并无不同,如果传入不安全的参数时,第一种使用#的方法查询不到结果(select * from user where id = ‘’ or 1=1),但这个参数在第二种也就是$下会得到全部的结果。
并且如果我们将sql进行打印,会发现添加#时,向数据库执行的sql为:select * from user where id = ’ ‘’ or 1=1 ',它会在我们的参数外再加一层引号,在使用$时,它的执行sql是select * from user where id = ‘’ or 1=1。
弃用$可以吗我们使用#也能完成的作用,并且使用的作用,并且使用还有危险,那么我们以后不使用$不就行了吗。
并不是,它只是在我们这种场景下会有问题,但是在有一些动态查询的场景中还是有不可代替的作用的,比如,动态修改表名select * from ${table} where id = #{id}。我们就可以在返回信息一致的情况下进行动态的更改查询的表,这也是mybatis动态强大的地方。
解决属性名和字段名不一致的问题 为什么不一致会出现问题1.MyBatis 会在幕后自动创建一个 ResultMap,再根据属性名来映射列到 JavaBean 的属性上。如果列名和属性名不能匹配上。查出来的值就会NULL。
2.可以在 SELECt 语句中设置列别名(这是一个基本的 SQL 特性)来完成匹配
对应的实体类:
private int id;
private String name;
private String password;
结果:User{id=1, name=‘张’, password=‘null’}
解决方案:起别名
结果:User{id=1, name=‘张’, password=‘123456’}
动态sql什么是动态sql:动态sql就是根据不同的条件生成不同的SQL语句
日志工厂 分页实现mybatis-04
思考:为什么要分页?
1.减少每一次的数据处理量
使用limit分页
公式:
SELECT * from user limit startIndex, endIndex;使用RowBounds



