Mybatis 学习笔记 -雷云龙
一 、mybatis概述
-
mybatis是java持久层框架,即是操作数据库的。内部封装了jdbc,只需要关注sql 本身
-
mybatis通过xml 或者注解 的方式将需要执行的statement配置起来,并通过java对象和statement中sql 的动态参数进行映射,最终生成完整的sql,最后mybatis 执行sql 并将结果映射成对象返回
-
采用ORM思想解决了实体和数据库映射的问题,对jdbc进行了封装
二、mybatis 入门
1、环境搭建
1.坐标
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
</dependencies>
2. entity
package com.maoni.entity;
import java.io.Serializable;
/**
* @Classbname : Books
* @Author : lyl
* @Date: 2020-01-07 15:25
*/
public class Books implements Serializable{
private Integer id;
private String bname;
private Double bprice;
private String bread;
private String manu;
private String db_source;
public Books() {
}
public Books(Integer id, String bname, Double bprice, String read, String manu, String db_source) {
this.id = id;
this.bname = bname;
this.bprice = bprice;
this.bread = read;
this.manu = manu;
this.db_source = db_source;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getbname() {
return bname;
}
public void setbname(String bname) {
this.bname = bname;
}
public Double getbprice() {
return bprice;
}
public void setbprice(Double bprice) {
this.bprice = bprice;
}
public String getRead() {
return bread;
}
public void setRead(String read) {
this.bread = read;
}
public String getManu() {
return manu;
}
public void setManu(String manu) {
this.manu = manu;
}
public String getDb_source() {
return db_source;
}
public void setDb_source(String db_source) {
this.db_source = db_source;
}
@Override
public String toString() {
return "Books{" +
"id=" + id +
", bname='" + bname + '\'' +
", bprice=" + bprice +
", read='" + bread + '\'' +
", manu='" + manu + '\'' +
", db_source='" + db_source + '\'' +
'}';
}
}
3. dao
package com.maoni.dao;
import com.maoni.entity.Books;
import java.util.List;
/**
* @ClassName : BoookDao
* @Author : lyl
* @Date: 2020-01-07 15:29
*/
public interface BookDao {
/**
* 查询所有
*/
List<Books> findAll();
}
4. 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">
<!--mybatis 的主配置文件-->
<configuration>
<!--配置环境-->
<environments default="mysql">
<!--配置mysql 环境-->
<environment id="mysql">
<!--配置事务-->
<transactionManager type="JDBC"/>
<!--配置数据源连接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybookshop?characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--指定映射配置文件的位置-->
<mappers>
<mapper resource="com/maoni/dao/BookDao-mapper.xml"/>
</mappers>
</configuration>
5. BookDao-mapper.xml
<?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">
<!--namespace 映射接口dao 所在的位置-->
<mapper namespace="com.maoni.dao.BookDao" >
<!--id 为接口中的方法名-->
<select id="findAll" resultType="com.maoni.entity.Books">
select * from goods_info
</select>
</mapper>
6 .注意:
创建映射文件目录时候,是多级目录,不是包.com/maoni/dao
7.测试类:
第一步:读取配置文件
第二步:创建SqlSessionFactory工厂
第三步:创建SqlSession
第四步:创建Dao接口的代理对象
第五步:执行dao中的方法
第六步:释放资源
注意事项:
不要忘记在映射配置中告知mybatis要封装到哪个实体类中
配置的方式:指定实体类的全限定类名
package com.maoni.test;
import com.maoni.dao.BookDao;
import com.maoni.entity.Books;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* @ClassName : Books
* @Author : lyl
* @Date: 2020-01-07 16:45
*/
public class BooksTest {
InputStream io = null;
SqlSession session = null;
//获取UserDao
BookDao bookDao = null;
@Before
public void before(){
try {
System.out.println("--------------------before");
//1.以流的形式读取mybatis_config.xml
io = Resources.getResourceAsStream("mybatis-config.xml");
//2.获取SqlsessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(io);
//3.获取SqlSession
session = factory.openSession();
//4.获取Dao
bookDao = session.getMapper(BookDao.class);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 查询所有用户信息
* try/catch:ctrl+alt+t
*/
@Test
public void findAll (){
//5.执行dao 中的方法获取查询到的数据
List<Books> books = bookDao.findAll();
System.out.println(books.toString());
}
@After
public void after(){
System.out.println("--------------------after");
try {
if(session!=null){
//关闭session
session.close();
}
if(io!=null){
//关闭流
io.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2、注解方式:
1.修改点
public interface BookDao {
/**
* 查询所有
*/
@select("select * from goods_info")
List<Books> findAll();
@select("select * from goods_info where bname like '%${value}%'")
List<Books> findByName(String BookName);
}
//就不需要mapper.xml 了
//config.xml修改:
<!--指定映射配置文件的位置-->
<mappers>
<mapper class="com.maoni.dao.BookDao"/> //class 指定的是dao 接口
</mappers>
三、全局配置文件config.xml
1、属性properties
用来引入外部的属性文件
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/javaee_authority?characterEncoding=utf8
db.username=root
db.password=root
<!--引入外部属性文件-->
<properties resource="db.properties"/>
2、设置settings
<settings> <setting name="" value=""/></settings>
https://mybatis.org/mybatis-3/zh/configuration.html#settings 使用文档
cacheEnabled | 全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存。 | true | false | true |
---|---|---|---|
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 |
true | false | false |
aggressiveLazyLoading | 当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载(参考 lazyLoadTriggerMethods )。 |
true | false | false (在 3.4.1 及之前的版本默认值为 true) |
multipleResultSetsEnabled | 是否允许单一语句返回多结果集(需要驱动支持)。 | true | false | true |
useColumnLabel | 使用列标签代替列名。不同的驱动在这方面会有不同的表现,具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果。 | true | false | true |
useGeneratedKeys | 允许 JDBC 支持自动生成主键,需要驱动支持。 如果设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能支持但仍可正常工作(比如 Derby)。 | true | false | False |
。。。。。。。。。。还有好多
3、类型别名(typeAliases)
类型别名是为 Java 类型设置一个短的名字。 它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余。例如:
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
<typeAlias alias="Comment" type="domain.blog.Comment"/>
<typeAlias alias="Post" type="domain.blog.Post"/>
<typeAlias alias="Section" type="domain.blog.Section"/>
<typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>
当这样配置时,Blog
可以用在任何使用 domain.blog.Blog
的地方。
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
<typeAliases>
<package name="domain.blog"/>
</typeAliases>
每一个在包 domain.blog
中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author
的别名为 author
;若有注解,则别名为其注解值。见下面的例子:
@Alias("author")
public class Author {
...
}
这是一些为常见的 Java 类型内建的相应的类型别名。它们都是不区分大小写的,注意对基本类型名称重复采取的特殊命名风格。
别名 | 映射的类型 |
---|---|
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
4、环境配置environments
必须要有dataSource 和transactionManager 环境才算完整,\
若需要连接多个数据库,那就需要配置多个环境才行,一个数据库对应一个环境
<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>
注意这里的关键点:
- 默认使用的环境 ID(比如:default=“development”)。
- 每个 environment 元素定义的环境 ID(比如:id=“development”)。
- 事务管理器的配置(比如:type=“JDBC”)。
- 数据源的配置(比如:type=“POOLED”)。
默认的环境和环境 ID 是自解释的,因此一目了然。 你可以对环境随意命名,但一定要保证默认的环境 ID 要匹配其中一个环境 ID。
数据源(dataSource)
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
- 许多 MyBatis 的应用程序会按示例中的例子来配置数据源。虽然这是可选的,但为了使用延迟加载,数据源是必须配置的。
有三种内建的数据源类型(也就是 type=”[UNPOOLED|POOLED|JNDI]”):
UNPOOLED– 这个数据源的实现只是每次被请求时打开和关闭连接。虽然有点慢,但对于在数据库连接可用性方面没有太高要求的简单应用程序来说,是一个很好的选择。 不同的数据库在性能方面的表现也是不一样的,对于某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形。
POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这是一种使得并发 Web 应用快速响应请求的流行处理方式。
JNDI – 这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。
5、数据库厂商标识(databaseIdProvider)
MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId
属性。 MyBatis 会加载不带 databaseId
属性和带有匹配当前数据库 databaseId
属性的所有语句。 如果同时找到带有 databaseId
和不带 databaseId
的相同语句,则后者会被舍弃。 为支持多厂商特性只要像下面这样在 mybatis-config.xml 文件中加入 databaseIdProvider
即可:
<databaseIdProvider type="DB_VENDOR" />
DB_VENDOR 对应的 databaseIdProvider 实现会将 databaseId 设置为 DatabaseMetaData#getDatabaseProductName()
返回的字符串。 由于通常情况下这些字符串都非常长而且相同产品的不同版本会返回不同的值,所以你可能想通过设置属性别名来使其变短,如下:
<databaseIdProvider type="DB_VENDOR">
<!--为不同数据库厂商取别名-->
<property name="SQL Server" value="sqlserver"/>
<property name="DB2" value="db2"/>
<property name="Oracle" value="oracle" />
</databaseIdProvider>
6、mappers
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
四、映射文件
cache
– 对给定命名空间的缓存配置。cache-ref
– 对其他命名空间缓存配置的引用。resultMap
– 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。sql
– 可被其他语句引用的可重用语句块。insert
– 映射插入语句update
– 映射更新语句delete
– 映射删除语句select
– 映射查询语句
1、select
查询语句是 MyBatis 中最常用的元素之一,光能把数据存到数据库中价值并不大,只有还能重新取出来才有用,多数应用也都是查询比修改要频繁。对每个插入、更新或删除操作,通常间隔多个查询操作。这是 MyBatis 的基本原则之一,也是将焦点和努力放在查询和结果映射的原因。简单查询的 select 元素是非常简单的。比如:
<select id="selectPerson" parameterType="int" resultType="hashmap">
SELECT * FROM PERSON WHERE ID = #{id}
</select>
属性 | 描述 |
---|---|
id |
在命名空间中唯一的标识符,可以被用来引用这条语句。 |
parameterType |
将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler) 推断出具体传入语句的参数,默认值为未设置(unset)。 |
resultType |
从这条语句中返回的期望类型的类的完全限定名或别名。 注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。可以使用 resultType 或 resultMap,但不能同时使用。 |
resultMap |
外部 resultMap 的命名引用。结果集的映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂映射的情形都能迎刃而解。可以使用 resultMap 或 resultType,但不能同时使用。 |
flushCache |
将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。 |
useCache |
将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。 |
timeout |
这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖驱动)。 |
fetchSize |
这是一个给驱动的提示,尝试让驱动程序每次批量返回的结果行数和这个设置值相等。 默认值为未设置(unset)(依赖驱动)。 |
statementType |
STATEMENT,PREPARED 或 CALLABLE 中的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。 |
resultSetType |
FORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖驱动)。 |
databaseId |
如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。 |
resultOrdered |
这个设置仅针对嵌套结果 select 语句适用:如果为 true,就是假设包含了嵌套结果集或是分组,这样的话当返回一个主结果行的时候,就不会发生有对前面结果集的引用的情况。 这就使得在获取嵌套的结果集的时候不至于导致内存不够用。默认值:false 。 |
resultSets |
这个设置仅对多结果集的情况适用。它将列出语句执行后返回的结果集并给每个结果集一个名称,名称是逗号分隔的。 |
2、insert, update 和 delete
数据变更语句 insert,update 和 delete 的实现非常接近:
<insert
id="insertAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
keyProperty=""
keyColumn=""
useGeneratedKeys=""
timeout="20">
<update
id="updateAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
timeout="20">
<delete
id="deleteAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
timeout="20">
属性 | 描述 |
---|---|
id |
命名空间中的唯一标识符,可被用来代表这条语句。 |
parameterType |
将要传入语句的参数的完全限定类名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器推断出具体传入语句的参数,默认值为未设置(unset)。 |
flushCache |
将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:true(对于 insert、update 和 delete 语句)。 |
timeout |
这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖驱动)。 |
statementType |
STATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。 |
useGeneratedKeys |
(仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段),默认值:false。 |
keyProperty |
(仅对 insert 和 update 有用)唯一标记一个属性,MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,默认值:未设置(unset )。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 |
keyColumn |
(仅对 insert 和 update 有用)通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望使用多个生成的列,也可以设置为逗号分隔的属性名称列表。 |
databaseId |
如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。 |
<insert id="insertAuthor">
insert into Author (id,username,password,email,bio)
values (#{id},#{username},#{password},#{email},#{bio})
</insert>
<update id="updateAuthor">
update Author set
username = #{username},
password = #{password},
email = #{email},
bio = #{bio}
where id = #{id}
</update>
<delete id="deleteAuthor">
delete from Author where id = #{id}
</delete>
3、获取主键
mysql 自增方式
<!--mysq1支持自增主键,自增主键值的获取,mybati s也是利用statement . getGenreatedKeys();
useGeneratedKeys="true";使用自增主键获取主键值策略
keyProperty;指定对应的主键属性,也就是mybati s获取到主键值以后,将这个值封装给javaBean的哪个属性
-->
<insert id= "addEmp" parameterType= "com. atguigu . mybatis. bean. Employee"
useGeneratedKeys= "true",keyProperty="id">
insert into tbl_ employee (1ast_ name ,email,gender)values (#{lastName}, #{email}, #{gender})
</insert>
Oracle 序列方式
<insert id="insertAuthor">
<selectKey keyProperty="id" resultType="int" order="BEFORE">
select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1
</selectKey>
insert into Author
(id, username, password, email,bio, favourite_section)
values
(#{id}, #{username}, #{password}, #{email}, #{bio}, #{favouriteSection,jdbcType=VARCHAR})
</insert>
运行顺序:先执行查询id 的语句,然后把查到的id 放入sql 语句中调用
属性 | 描述 |
---|---|
keyProperty |
selectKey 语句结果应该被设置的目标属性。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 |
keyColumn |
匹配属性的返回结果集中的列名称。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 |
resultType |
结果的类型。MyBatis 通常可以推断出来,但是为了更加精确,写上也不会有什么问题。MyBatis 允许将任何简单类型用作主键的类型,包括字符串。如果希望作用于多个生成的列,则可以使用一个包含期望属性的 Object 或一个 Map。 |
order |
这可以被设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它会首先生成主键,设置 keyProperty 然后执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 中的语句 - 这和 Oracle 数据库的行为相似,在插入语句内部可能有嵌入索引调用。 |
statementType |
与前面相同,MyBatis 支持 STATEMENT,PREPARED 和 CALLABLE 语句的映射类型,分别代表 PreparedStatement 和 CallableStatement 类型。 |
4、自定义结果集映射
1. resultType结果类型
自动映射
特点:实体类属性必须和数据库表列名一致
2. resultMap 结果类型
特点:实体类属性可以和数据库表列名不一致
type 属性:指定实体类的全限定类名
id 属性:给定一个唯一标识,是给查询 select 标签引用用的。
-->
<resultMap type="com.yueqian.domain.User" id="userMap">
<id column="id" property="userId"/>
<result column="username" property="userName"/>
<result column="sex" property="userSex"/>
<result column="address" property="userAddress"/>
<result column="birthday" property="userBirthday"/>
<result column="bid" property="dep.id"/>
</resultMap>
id 标签:用于指定主键字段
result 标签:用于指定非主键字段
column 属性:用于指定数据库列名
property 属性:用于指定实体类属性名称
注解:
/**
* 查询所有用户
* @return
*/
@Select("select * from t_employee")
@Results(
id = "findEmployeeResultMap",
value = {
@Result(id = true,column = "id",property = "id"),
@Result(column = "username",property = "username"),
@Result(column = "password",property = "password"),
@Result(column = "realName",property = "realName"),
@Result(column = "tel",property = "tel"),
@Result(column = "email",property = "email"),
@Result(column = "inputTime",property = "inputTime"),
@Result(column = "state",property = "state"),
@Result(column = "imagePic",property = "imagePic"),
@Result(column = "id",property = "roles",
many = @Many(select = "com.dwj.javaee_project.dao.RoleDao.findRoleByEmployeeId",fetchType = FetchType.LAZY))
}
)
public List<Employee> findEmployee();
五、传参
1、单个参数
#{参数名}
2、多个参数
mybatis 会对多个参数进行特殊处理,会封装成map,然后#{ } 就是从map 中取出指定key 的值,
key: pram1,prame2 … 或者索引
value : 传入的参数值
<select id="findByMany" parameterType="java.lang.String" resultType="com.maoni.entity.Books">
select * from goods_info where bname = #{primary1 } and bprice = #{primary2 }
</select>
3、命名参数
在java代码传参时候,明确指定参数。@primary(" id")
这样就把传入的参数作为 map 的 key值
/*** Dao
* 命名参数
* @param BookName
* @return
*/
List<Books> findByMany(@Param("bname") String BookName, @Param("bprice") double price);
@Test
public void findByMany(){
List<Books> books = bookDao.findByMany("三国演义",220);
System.out.println(books);
}
<!--mapper.xml-->
<select id="findByMany" parameterType="java.lang.String" resultType="com.maoni.entity.Books">
select * from goods_info where bname = #{bname } and bprice = #{bprice }
</select>
4、POJO参数
如果多个参数是POJO的属性,那么可以直接 ${ 属性 } 获取参数,
如果多个参数不是POJO 属性,那么可以直接传入map
#{ key }
5、# 与 $ 的区别
#{ } :是以预编译的形式,将参数设置到sql 语句中,PreperdStatement,防止SQL 注入
${ } : 取出的值会直接拼装在 SQL语句中,会有安全问题
大多数情况下,都会用#{};
原生SQL 不支持占位符的地方,可以使用${ } 进行取值
分表、排序等
六、动态SQL
1、if<>标签
Dao:
List<User> findByUser(User user);
xml
<select id="findByUser" resultType="user" parameterType="user">
select * from user where 1=1
<if test="username!=null and username != '' ">
and username like "%"#{username}"%"
</if>
<if test="address != null">
and address like "%"#{address}"%"
</if>
</select>
注意:<if>标签的 test 属性中写的是对象的属性名,如果是包装类的对象要使用 OGNL 表达式的写法。
另外要注意 where 1=1 的作用~!
2、choose<>标签
<select id="findByUser" resultType="user" parameterType="user">
select * from user where 1=1
<choose>
<when test="username!=null and username != '' ">
and username like "%"#{username}"%"
</when>
<when test="address != null">
and address like "%"#{address}"%"
</when>
<otherwise>
........
</otherwise>
</select>
3、where<>标签
<!-- 根据用户信息查询 -->
<select id="findByUser" resultType="user" parameterType="user">
<include refid="defaultSql"></include>
<where>
<if test="username!=null and username != '' ">
and username like "%"#{username}"%"
</if>
<if test="address != null">
and address like"%"#{address}"%"
</if>
</where>
</select>
4、set<>标签
<update id="updateUser" parmeterType="user">
update user
<set>
<if test="username!=null and username != '' ">
username =${username},
</if>
<if test="address != null">
address =${address},
</if>
</where>
</select>
5、foreach<>标签
需求:
传入多个 id 查询用户信息,用下边两个 sql 实现:
SELECT * FROM USERS WHERE username LIKE ‘%张%’ AND (id =10 OR id =89 OR id=16)
SELECT * FROM USERS WHERE username LIKE ‘%张%’ AND id IN (10,89,16)
<!-- 查询所有用户在 id 的集合之中 -->
<select id="findInIds" resultType="user" parameterType="queryvo">
<!-- select * from user where id in (1,2,3,4,5); -->
<include refid="defaultSql"></include>
<where>
<if test="ids != null and ids.size() > 0">
<foreach collection="ids" open="id in ( " close=")" item="uid"separator=",">
#{uid}
</foreach>
</if>
</where>
</select>
SQL 语句:
select 字段 from user where id in (?)
<foreach>标签用于遍历集合,它的属性:
collection:代表要遍历的集合元素,注意编写时不要写#{}
open:代表语句的开始部分
close:代表结束部分
item:代表遍历集合的每个元素,生成的变量名
sperator:代表分隔符
<!-- MySQL下批量保存:-->
<!--批量保存方式一 -->
<!--public void addEmps (@Param("emps")List<Employee> emps) ;-->
<insert id= "addEmps ">
insert into tb1_emp1oyee (1ast_name, email, gender,d_id)
values
<foreach collection= "emps" item= "emp"separator=",">
(#{emp.lastName}, #{ emp.email} ,#{emp.gender}, #{ emp.dept.id})
</foreach>
</ insert>
<!--批量保存方式二 -->
<!--这种方式需要数据库连接属性allowMultiQueries=true -->
<insert id= "addEmps">
<foreach collection="emps" item= "emp" separator=";">
insert into tbl_ employee(last_name,email, gender,d_id)
values (#{ emp.lastName}, #{ emp.email}, #{ emp.gender}, #{ emp.dept.id
</foreach>
</ insert>
<!--oracle下 -->
<!--批量保存方式二 -->
<!--1、多个insert放在begin - end里面-->
begin
insert into employees (employee_id,last_name,email)
values( employees_seq. nextval, 'test_001' ,'test_001@atguigu')
insert into employees ( employee_id,last_name, email )
values ( employees_seq. nextval, 'test_002', 'test_002@atguigu')
end;
<!--2、利用中间表-->
6、SQL片段
Sql 中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的。
<!-- 抽取重复的语句代码片段 -->
<sql id="defaultSql">
select * from user
</sql>
<!-- 配置查询所有操作 -->
<select id="findAll" resultType="user">
<include refid="defaultSql"></include>
</select>
<!-- 根据 id 查询 -->
<select id="findById" resultType="UsEr" parameterType="int">
<include refid="defaultSql"></include>
where id = #{uid}
</select>
七、连接池和事务
。。。
曾删改需要提交事务
commit()提交
rollback(); 回滚
八、关联映射
1、多对一,也就是一对一
one = @one(select = “com.dwj.javaee_project.dao.RoleDao.findRoleByEmployeeId”,fetchType = FetchType.LAZY))
/**
* 查询所有用户
* @return
*/
@Select("select * from t_employee")
@Results(
id = "findEmployeeResultMap",
value = {
@Result(id = true,column = "id",property = "id"),
@Result(column = "username",property = "username"),
@Result(column = "password",property = "password"),
@Result(column = "realName",property = "realName"),
@Result(column = "tel",property = "tel"),
@Result(column = "email",property = "email"),
@Result(column = "inputTime",property = "inputTime"),
@Result(column = "state",property = "state"),
@Result(column = "imagePic",property = "imagePic"),
@Result(column = "id",property = "roles",
one = @one(select = "com.dwj.javaee_project.dao.RoleDao.findRoleByEmployeeId",fetchType = FetchType.LAZY))
}
)
public List<Employee> findEmployee();
2、一对多
many = @Many(select = “com.dwj.javaee_project.dao.RoleDao.findRoleByEmployeeId”,fetchType = FetchType.LAZY)) 一对多懒加载
/**
* 查询所有用户
* @return
*/
@Select("select * from t_employee")
@Results(
id = "findEmployeeResultMap",
value = {
@Result(id = true,column = "id",property = "id"),
@Result(column = "username",property = "username"),
@Result(column = "password",property = "password"),
@Result(column = "realName",property = "realName"),
@Result(column = "tel",property = "tel"),
@Result(column = "email",property = "email"),
@Result(column = "inputTime",property = "inputTime"),
@Result(column = "state",property = "state"),
@Result(column = "imagePic",property = "imagePic"),
@Result(column = "id",property = "roles",
many = @Many(select = "com.dwj.javaee_project.dao.RoleDao.findRoleByEmployeeId",fetchType = FetchType.LAZY))
}
)
public List<Employee> findEmployee();
九、延迟加载
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
十、缓存机制
MyBatis系统中默认定义了两级缓存。
一级缓存和二级缓存。
-
默认情况下,只有一级缓存(SqlSession级别的缓存也称为本地缓存)开启。
-
二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
-
为了提高扩展性。MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存
1、一级缓存(本地缓存)
与数据库一次会话期间查询到的数据放在本地缓存中,如果需要相同的数据,直接从缓存中拿,没必要再去访问数据库。默认是一直开启的。
一级缓存失效的四种情况:
- sqlSsion不同
- sqlSsion 相同,但是查询条件不同
- sqlSsion 相同,两次查询之间执行了增删改
- sqlSsion 相同,但是手动清除缓存了
2、二级缓存(全局缓存)
是基于 namespace 级别的缓存。一个namespace对应一个二级缓存
工作机制:
一次会话,查询到的数据就会放到当前会话的一级缓存中;
如果会话关闭,一级缓存中的数据会被保存到二级缓存中去。
使用:
1.开启:
<!--开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
@CacheNamespace( blocking = true)
public interface BookDao {}
2.mapper.xml 中使用
<cache eviction="" blocking="" flushInterval="" readOnly="" size="" type=""></cache>
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
每个select 标签都有useCache ="true"
eviction清除刷新
可用的清除策略有:
LRU
– 最近最少使用:移除最长时间不被使用的对象。FIFO
– 先进先出:按对象进入缓存的顺序来移除它们。SOFT
– 软引用:基于垃圾回收器状态和软引用规则移除对象。WEAK
– 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
默认的清除策略是 LRU。
**flushInterval(刷新间隔)**属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。
**size(引用数目)**属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。
**readOnly(只读)**属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。
3.实体类需要序列化
十一、mybatis的注解形式
config.xml 修改点
<mappers>
<!--指定映射配置文件的位置-->
<!-- <mapper resource="com/maoni/dao/BookDao-mapper.xml"/>-->
<!--指定带有注解的接口所在位置-->
<package name="com.tydic.dao"/>
</mappers>
Dao 层,注解配置取代mapper.xml的配置
package com.tydic.dao;
import com.tydic.entity.Book;
import com.tydic.provider.BookProvider;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* dao层控制
* @author: tydic 雷云龙
* @time: 2019/11/20
*/
public interface IBookDao{
/*查询所有*/
@Select("select * from goods_info")
@Results(
id = "findAllBookMap",
value = {
@Result(id = true,column = "id",property = "id"),// id = true 说明是住建
@Result(column = "bname",property = "name"),
@Result(column = "bprice",property = "price"),
@Result(column = "bread",property = "read"),
@Result(column = "manu",property = "manu"),
@Result(column = "db_source",property = "db_source")
}
)
public List<Book> findAll();
/*通过ID查询*/
@Select("select * from goods_info where id=#{id}")
@ResultMap("findAllBookMap")
public Book findById(Integer id);
/*添加*/
@Insert(" insert into goods_info(bname,bprice,bread,manu,db_source) values(#{bname},#{bprice}#{bread}#{manu},DATABASE());")
public boolean addBook(Book book);
/*更新*/
@UpdateProvider(type = BookProvider.class,method = "updateBook")
//@Update("update goods_info set(bname,bprice,bread,manu) values(#{bname},#{bprice}#{bread}#{manu}); ")
public boolean updateBook(Book book);
/*刪除*/
@Delete("delete from goods_info where id= #{id}")
public boolean deleteBook( @Param("id") Integer id);
}
十二、整合Spring
后续。。。。
来源:CSDN
作者:레이윈룽
链接:https://blog.csdn.net/qwd_as_dsd_as/article/details/104063620