目录
3.2.6 在src源码目录下创建mybatis的核心配置文件 mybatis-config.xml
9、mybatis的核心配置之databaseIdProvider
12.6.2、MySQL的字符串拼接,concat函数实现。
14.4、choose( when , otherwise )语句
15.2.3、flushCache="false"的演示和说明
1.MyBatis简介
MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。
MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录(就像是传统的JDBC一样,用来连接数据库)。
要学习Mybatis前先得了解ORM、JPA的概念:
ORM(Object-Relationship-Mapping):是对象关系映射的意思,它是一种思想,是指将数据库中的每一行数据用对象的形式表现出来。
JPA(Java-Persistence-API):是Java持久化接口的意思,它是JavaEE关于ORM思想的一套标准接口,仅仅是一套接口,不是具体的实现。
2.MyBatis的优缺点
1.SQL语句与代码分离,存放于xml配置文件中:
优点:便于维护管理,不用在java代码中找这些语句;
缺点: JDBC方式可以用用打断点的方式调试,但是Mybatis不能,需要通过log4j日志输出日志信息帮助调试,然后在配置文件中修改。
2.用逻辑标签控制动态SQL的拼接:
优点:用标签代替编写逻辑代码;
缺点:拼接复杂SQL语句时,没有代码灵活,拼写比较复杂。不要使用变通的手段来应对这种复杂的语句。
3.查询的结果集与java对象自动映射:
优点:保证名称相同,配置好映射关系即可自动映射或者,不配置映射关系,通过配置列名=字段名也可完成自动映射。
缺点:对开发人员所写的SQL依赖很强。
4.编写原生SQL:
优点:接近JDBC,比较灵活。
缺点:对SQL语句依赖程度很高;并且属于半自动,数据库移植比较麻烦,比如mysql数据库编程Oracle数据库,部分的sql语句需要调整。
3.MyBatis示例
3.1、创建一个数据库和一个单表
drop database if exists mybatis;
create database mybatis;
use mybatis;
##############################################################################
################################### 单表 ######################################
##############################################################################
## 创建单表
create table t_user(
`id` int primary key auto_increment,
`last_name` varchar(50),
`sex` int
);
insert into t_user(`last_name`,`sex`) values('zhangsan',1);
select * from t_user;
JavaBean类 以前 Mybatis中是
User UserDao UserMapper
Book BookDao BookMapper
在Mybatis中使用Mapper接口习惯命名如下(Mybatis中不需要自己写实现类):
JavaBean类 Dao( Mapper )接口名 sql语句的配置文件名
User UserMapper UserMapper.xml
Book BookMapper BookMapper.xml
3.2程序示例:
3.2.1 创建一个java模块:
3.2.2 导入需要的jar包:
junit_4.12.jar
log4j-1.2.17.jar
mybatis-3.5.1.jar
mysql-connector-java-5.1.7-bin.jar
org.hamcrest.core_1.3.0.jar
3.2.3 数据库表对应的JavaBean
public class User {
private Integer id;
private String lastName;
private Integer sex;
3.2.4 编写Mapper接口:
public interface UserMapper {
/**
* 根据id查询用户信息
*
* @param id 用户的id
* @return
*/
public User selectUserById(Integer id);
}
3.2.5.编写sql的配置文件:
<?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是名称空间,它的取值必须是对应的接口的全类名
-->
<mapper namespace="com.demo.mapper.UserMapper">
<!--
select 标签用来配置select查询语句
id 属性配置一个唯一的标识
resultType 是查询后每一行记录封装的对象类型
#{id} 它是占位符 ?
-->
<select id="selectUserById" resultType="com.demo.pojo.User">
select `id`,`last_name` lastName,`sex` from t_user where id = #{id}
</select>
</mapper>
3.2.6 在src源码目录下创建mybatis的核心配置文件 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>
<!--
environments 表示配置数据库环境
-->
<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"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- mybatis 是把sql配置到xml配置文件中
下面的配置是告诉Mybatis到哪里加载sql的配置文件
-->
<mappers>
<mapper resource="com/demo/mapper/UserMapper.xml"/>
</mappers>
</configuration>
3.2.7 测试代码:
public class MybatisTest {
@Test
public void test() throws IOException {
// 先由Mybatis的核心配置文件mybatis-config.xml创建sqlSessionFactory类
/**
* Resources类用于读取mybatis的核心配置文件
*/
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
// SqlSessionFactoryBuilder专门用于创建SqlSessionFactory类
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
System.out.println(sqlSessionFactory);
}
@Test
public void test2() throws IOException {
// 测试的目标是,执行select * from t_user where id = 1 将数据查询出来.并封装成为User对象返回
//1 由mybatis的核心配置文件创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
//2 再由SqlSessionFactory对象创建SqlSession( SqlSession对象相当于JDBC编程中的Connection连接对象,每次用完要关闭 )
SqlSession session = sqlSessionFactory.openSession();
try {
//3 通过SqlSession获取Mapper的实现类
UserMapper mapper = session.getMapper(UserMapper.class);
//4 调用Mapper方法
User user = mapper.selectUserById(1);
System.out.println( user );
} finally {
session.close();
}
}
}
Mybatis框架Mapper接口开发时的注意事项有:
1 Mapper接口必须要和Mapper.xml中名称空间值一致
2 Mapper接口的方法名必须要和Mapper.xml中的id值一致
3 Mapper接口的参数类型必须要和Mapper.xml中的parameterType类型一致
4 Mapper接口的返回值类型必须要和Mapper.xml中的resultType类型一致
4.接口实现CRUD
4.1Mapper接口代码:
/**
* UserMapper它的实现类是由Mybatis底层源码进行了实现( jdk动态代理 )
*/
public interface UserMapper {
/**
* 根据id查询用户信息
*
* @param id 用户的id
* @return
*/
public User selectUserById(Integer id);
/**
* 查询全部
*
* @return
*/
public List<User> selectAll();
/**
* 更新用户
*
* @param user
* @return
*/
public int updateUser(User user);
/**
* 删除用户
*
* @param id
* @return
*/
public int deleteUserById(Integer id);
/**
* 插入用户
*
* @param user
* @return
*/
public int insertUser(User user);
}
4.2Mapper.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是名称空间,它的取值必须是对应的接口的全类名
-->
<mapper namespace="com.demo.mapper.UserMapper">
<!--
select 标签用来配置select查询语句
id 属性配置一个唯一的标识
resultType 是查询后每一行记录封装的对象类型
parameterType 表示参数类型 ( 可选的 ) ,一般情况下,如果是一个参数.而且是JavaBean建议写上
int 表示==>>> java.lang.Integer
#{id} 它是占位符 ?
-->
<select id="selectUserById" resultType="com.demo.pojo.User">
select `id`,`last_name` lastName,`sex` from t_user where id = #{id}
</select>
<!-- /**
* 查询全部
*
* @return
*/
public List<User> selectAll();
resultType 是表示查询回来之后每一行记录转换为什么类型的对象
-->
<select id="selectAll" resultType="com.demo.pojo.User">
select `id`,`last_name` lastName,`sex` from t_user
</select>
<!-- /**
* 更新用户
*
* @param user
* @return
*/
public int updateUser(User user);
parameterType 和 resultType 都是在JavaBean类型的时候才写.
-->
<update id="updateUser" parameterType="com.demo.pojo.User">
update
t_user
set
`last_name` = #{lastName} ,
`sex` = #{sex}
where
id = #{id}
</update>
<!-- /**
* 删除用户
*
* @param id
* @return
*/
public int deleteUserById(Integer id);-->
<delete id="deleteUserById">
delete from t_user where id = #{id}
</delete>
<!-- /**
* 插入用户
*
* @param user
* @return
*/
public int insertUser(User user);-->
<insert id="insertUser" parameterType="com.demo.pojo.User">
insert into
t_user(`last_name`,`sex`)
values
(#{lastName},#{sex})
</insert>
</mapper>
4.3测试的代码:
public class UserMapperTest {
static SqlSessionFactory sqlSessionFactory;
/**
* @BeforeClass 可以在Junit测试是标识一个static方法用于做初始化使用.<br/>
* 1 标识了@BeforeClass注解的方法会在测试方法之前自动执行
* @throws Exception
*/
@BeforeClass
public static void setUp() throws Exception {
System.out.println("beforeClass()");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(
Resources.getResourceAsStream("mybatis-config.xml"));
}
@Test
public void selectUserById() {
// SqlSession相当于 Jdbc 编程中的Connection连接对象,每次使用完一定要*及时*关闭
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectUserById(1);
System.out.println(user);
} finally {
session.close();
}
}
@Test
public void selectAll() {
// SqlSession相当于 Jdbc 编程中的Connection连接对象,每次使用完一定要*及时*关闭
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
for (User user : mapper.selectAll()) {
System.out.println(user);
}
} finally {
session.close();
}
}
@Test
public void updateUser() {
// SqlSession相当于 Jdbc 编程中的Connection连接对象,每次使用完一定要*及时*关闭
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
mapper.updateUser(new User(2, "bbj", 1));
session.commit();//手动提交事务
} finally {
session.close();
}
}
@Test
public void deleteUserById() {
// SqlSession相当于 Jdbc 编程中的Connection连接对象,每次使用完一定要*及时*关闭
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
mapper.deleteUserById(2);
session.commit();
} finally {
session.close();
}
}
@Test
public void insertUser() {
// SqlSession相当于 Jdbc 编程中的Connection连接对象,每次使用完一定要*及时*关闭
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
mapper.insertUser(new User(0,"bbj168", 1));
session.commit();
} finally {
session.close();
}
}
}
4.4返回自增的主键
<!-- /**
* 插入用户
*
* @param user
* @return
*/
public int insertUser(User user);
useGeneratedKeys="true" 表示使用( 返回 )数据库自增的主键值
use 使用
Generated 生成的
keys 主键
keyProperty="id" 表示将返回的主键值注入到id属性中
-->
<insert id="insertUser" useGeneratedKeys="true"
keyProperty="id" parameterType="com.demo.pojo.User">
insert into
t_user(`last_name`,`sex`)
values
(#{lastName},#{sex})
</insert>
4.5<selectKey> 标签的使用
selectKey是一个标签,常用于在insert标签里配置一个查询操作. 也是经常用来查询插入后生成的主键值.
<insert id="insertUser" parameterType="com.demo.pojo.User">
<!--
select select查询
Key 主键
last_insert_id() 是一个函数.它会返回最后一次生成的主键值
order 设置selectKey的语句是先执行,还是后执行.
BEFORE selectKey先执行
AFTER selectKey后执行
keyProperty="id" 表示将返回的主键值注入到id属性中
resultType 设置返回的主键的类型 Integer
-->
<selectKey order="AFTER" keyProperty="id" resultType="int">
select last_insert_id()
</selectKey>
insert into
t_user(`last_name`,`sex`)
values
(#{lastName},#{sex})
</insert>
4.6注解@MapKey的使用。
@MapKey可以将查询回来的JavaBean以注解给定的属性做为key,封装为一个Map对象返回.
Mapper接口
/**
* 查询全部的对象,并以id做为key封装为Map返回 <br/>
* 一个entry 一条记录 <br>
* key 指定的id属性值 <br/>
* value 就是一行记录的JavaBean <br/>
* @return
*/
@MapKey("id")
public Map<Integer,User> selectAllForMap();
Mapper.xml配置文件:
<!-- /**
* 查询全部的对象,并以id做为key封装为Map返回 <br/>
* @return
*/
public Map<Integer,User> selectAllForMap();
resultType属性还是将每一行返回的记录封装成为什么类型的对象
-->
<select id="selectAllForMap" resultType="com.demo.pojo.User" >
select `id`,`last_name` lastName,`sex` from t_user
</select>
测试代码:
@Test
public void selectAllForMap() {
// SqlSession相当于 Jdbc 编程中的Connection连接对象,每次使用完一定要*及时*关闭
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
Map<Integer, User> integerUserMap = mapper.selectAllForMap();
for ( Map.Entry<Integer, User> entry : integerUserMap.entrySet() ) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
} finally {
session.close();
}
}
5、mybatis的核心配置之properties
<!--
properties 表示复数(多组键值对)
resource属性表示读取(引用) 指定properties属性配置文件的键值对
-->
<properties resource="jdbc.properties">
<!-- <property name="user" value="root"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>-->
</properties>
<!--
environments 表示配置数据库环境
-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!-- 数据库驱动 -->
<property name="driver" value="${driverClassName}"/>
<property name="url" value="${url}"/>
<property name="username" value="${user}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
6、mybatis的核心配置之settings
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。下表描述了设置中各项的意图、默认值等。
6.1、所有mybatis的settings设置选项
设置参数 | 描述 | 有效值 | 默认值 |
cacheEnabled | 该配置影响的所有映射器中配置的缓存的全局开关。 | true | false | true |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。 | true | false | false |
aggressiveLazyLoading | 当启用时,对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;反之,每种属性将会按需加载。 | true | false | true |
multipleResultSetsEnabled | 是否允许单一语句返回多结果集(需要兼容驱动)。 | true | false | true |
useColumnLabel | 使用列标签代替列名。不同的驱动在这方面会有不同的表现, 具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果。 | true | false | true |
useGeneratedKeys | 允许 JDBC 支持自动生成主键,需要驱动兼容。 如果设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工作(比如 Derby)。 | true | false | False |
autoMappingBehavior | 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示取消自动映射;PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。 FULL 会自动映射任意复杂的结果集(无论是否嵌套)。 | NONE, PARTIAL, FULL | PARTIAL |
autoMappingUnknownColumnBehavior | Specify the behavior when detects an unknown column (or unknown property type) of automatic mapping target.
| NONE, WARNING, FAILING | NONE |
defaultExecutorType | 配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新。 | SIMPLE REUSE BATCH | SIMPLE |
defaultStatementTimeout | 设置超时时间,它决定驱动等待数据库响应的秒数。 | Any positive integer | Not Set (null) |
defaultFetchSize | Sets the driver a hint as to control fetching size for return results. This parameter value can be override by a query setting. | Any positive integer | Not Set (null) |
safeRowBoundsEnabled | 允许在嵌套语句中使用分页(RowBounds)。 If allow, set the false. | true | false | False |
safeResultHandlerEnabled | 允许在嵌套语句中使用分页(ResultHandler)。 If allow, set the false. | true | false | True |
mapUnderscoreToCamelCase | 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。 | true | false | False |
localCacheScope | MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。 默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。 | SESSION | STATEMENT | SESSION |
jdbcTypeForNull | 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。 | JdbcType enumeration. Most common are: NULL, VARCHAR and OTHER | OTHER |
lazyLoadTriggerMethods | 指定哪个对象的方法触发一次延迟加载。 | A method name list separated by commas | equals,clone,hashCode,toString |
defaultScriptingLanguage | 指定动态 SQL 生成的默认语言。 | A type alias or fully qualified class name. | org.apache.ibatis.scripting.xmltags.XMLDynamicLanguageDriver |
callSettersOnNulls | 指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这对于有 Map.keySet() 依赖或 null 值初始化的时候是有用的。注意基本类型(int、boolean等)是不能设置成 null 的。 | true | false | false |
logPrefix | 指定 MyBatis 增加到日志名称的前缀。 | Any String | Not set |
logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | Not set |
proxyFactory | 指定 Mybatis 创建具有延迟加载能力的对象所用到的代理工具。 | CGLIB | JAVASSIST | JAVASSIST (MyBatis 3.3 or above) |
vfsImpl | Specifies VFS implementations | Fully qualified class names of custom VFS implementation separated by commas. | Not set |
useActualParamName | Allow referencing statement parameters by their actual names declared in the method signature. To use this feature, your project must be compiled in Java 8 with -parameters option. (Since: 3.4.1) | true | false | true |
mybatis的核心配置之typeAliases
<!--
type 类型
Aliases 别名
-->
<typeAliases>
<!--
typeAlias标签给一个具体类型起别名
type是具体的类型
alias是别名
<typeAlias type="com.demo.pojo.User" alias="user" />-->
<!--
package标签通过指定一个包名,一次性自动的给指定包名下所有类都加上别名
别名是啥?
别名是类名,以及类名首字母小写
-->
<package name="com.demo.pojo"/>
<package name="com.demo.entity"/>
</typeAliases>
7.1.系统提示的预定义别名
已经为许多常见的 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 |
mybatis的核心配置之typeHandlers
类型处理器主要就是用来设置sql语句中的占位符的参数值.以及获取查询结果集中的值.
类型处理器 | Java 类型 | JDBC 类型 |
BooleanTypeHandler | java.lang.Boolean, boolean | 数据库兼容的 BOOLEAN |
ByteTypeHandler | java.lang.Byte, byte | 数据库兼容的 NUMERIC 或 BYTE |
ShortTypeHandler | java.lang.Short, short | 数据库兼容的 NUMERIC 或 SHORT INTEGER |
IntegerTypeHandler | java.lang.Integer, int | 数据库兼容的 NUMERIC 或 INTEGER |
LongTypeHandler | java.lang.Long, long | 数据库兼容的 NUMERIC 或 LONG INTEGER |
FloatTypeHandler | java.lang.Float, float | 数据库兼容的 NUMERIC 或 FLOAT |
DoubleTypeHandler | java.lang.Double, double | 数据库兼容的 NUMERIC 或 DOUBLE |
BigDecimalTypeHandler | java.math.BigDecimal | 数据库兼容的 NUMERIC 或 DECIMAL |
StringTypeHandler | java.lang.String | CHAR, VARCHAR |
ClobReaderTypeHandler | java.io.Reader | - |
ClobTypeHandler | java.lang.String | CLOB, LONGVARCHAR |
NStringTypeHandler | java.lang.String | NVARCHAR, NCHAR |
NClobTypeHandler | java.lang.String | NCLOB |
BlobInputStreamTypeHandler | java.io.InputStream | - |
ByteArrayTypeHandler | byte[] | 数据库兼容的字节流类型 |
BlobTypeHandler | byte[] | BLOB, LONGVARBINARY |
DateTypeHandler | java.util.Date | TIMESTAMP |
DateOnlyTypeHandler | java.util.Date | DATE |
TimeOnlyTypeHandler | java.util.Date | TIME |
SqlTimestampTypeHandler | java.sql.Timestamp | TIMESTAMP |
SqlDateTypeHandler | java.sql.Date | DATE |
SqlTimeTypeHandler | java.sql.Time | TIME |
ObjectTypeHandler | Any | OTHER 或未指定类型 |
EnumTypeHandler | Enumeration Type | VARCHAR-任何兼容的字符串类型,存储枚举的名称(而不是索引) |
EnumOrdinalTypeHandler | Enumeration Type | 任何兼容的 NUMERIC 或 DOUBLE 类型,存储枚举的索引(而不是名称)。 |
-
mybatis的核心配置之environments
environments标签配置的是数据库环境
8.1、environments 标签说明
8.2、transactionManager 标签说明
表示使用哪种类型的事务
- JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
- MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为
8.3、dataSource 标签说明
type 属性的值有三种: UNPOOLED 、 POOLED 、 JNDI。自定义(实现DataSourceFactory接口)
UNPOOLED– 不使用数据库连接池,每次使用才打开一个,用完关闭
POOLED 使用数据库连接池
9、mybatis的核心配置之databaseIdProvider
MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。 MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的所有语句。
<databaseIdProvider type="DB_VENDOR">
<property name="SQL Server" value="sqlserver" />
<property name="MySQL" value="mysql" />
<property name="DB2" value="db2" />
<property name="Oracle" value="oracle" />
</databaseIdProvider>
9.1、databaseId测试
<select id="selectAll" resultType="user">
select `id`,`last_name`,`sex` from t_user
</select>
<!--
databaseId="mysql" 表示如果我的数据库是mysql,就会使用下面配置的这个语句
-->
<select id="selectAll" resultType="user" databaseId="mysql">
select `id`,`last_name`,`sex` from t_user where 1 = 1
</select>
<!--
databaseId="oracle" 表示如果我的数据库是mysql,就会使用下面配置的这个语句
-->
<select id="selectAll" resultType="user" databaseId="oracle">
select `id`,`last_name`,`sex` from t_user where 2 = 2
</select>
10、mybatis的核心配置之Mappers
按照类路径加载
按照接口,或给定包名加载
-
注解配置sql
注解方式可以和xml方式共用,但是注意一个方法要么使用注解方式配置sql,要么使用xml方式配置sql,不能两种都给同一个方法配置sql.
public interface UserMapper {
@Select("select `id`,`last_name`,`sex` from t_user where id = #{id}")
public User selectUserById(Integer id);
@Select("select `id`,`last_name`,`sex` from t_user")
public List<User> selectAll();
@Update("update t_user set `last_name` = #{lastName} , `sex` = #{sex} where id = #{id}")
public int updateUser(User user);
@Delete("delete from t_user where id = #{id}")
public int deleteUserById(Integer id);
/**
* @SelectKey注解相当于之前的selectKey标签 <br/>
* statement属性是sql语句 <br/>
* before属性设置是否先执行selectKey标签的sql语句 <br/>
* keyProperty属性设置返回的主键值注入到JavaBean的哪个属性中<br/>
* @param user
* @return
*/
@SelectKey(statement = "select last_insert_id()",before = false,keyProperty = "id",resultType = Integer.class)
@Insert("insert into t_user(`last_name`,`sex`) values(#{lastName},#{sex})")
public int insertUser(User user);
}
-
mybatis的参数传递
参数传递指的是,如何将接口调用时传递的参数时,注入到sql语句的#{}占位符中
12.1、一个普通数据类型
Mapper接口
public interface UserMapper {
public User selectUserById(Integer id);
}
Mapper.xml配置文件:
<!-- public User selectUserById(Integer id);
如果你的方法只有一个参数,并且是普通数据类型.只需要在#{}中写上参数名即可 <br/>
如果只有一个参数的时候,其实在#{}中可以任意书写,推荐写参数名
-->
<select id="selectUserById" resultType="com.demo.pojo.User">
select `id`,`last_name`,`sex` from t_user where id = #{id}
</select>
测试的代码:
public class UserMapperTest {
static SqlSessionFactory sqlSessionFactory;
@BeforeClass
public static void init() throws IOException {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(
Resources.getResourceAsStream("mybatis-config.xml")
);
}
@Test
public void selectUserById() {
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = userMapper.selectUserById(1);
System.out.println(user);
} finally {
session.close();
}
}
}
12.2、多个普通数据类型
Mapper接口:
/**
* 根据给定的name或sex值来查询用户信息 <br/>
* @return
*/
public List<User> selectUsersByNameOrSex(String name,Integer sex);
Mapper.xml配置文件:
<!--
public List<User> selectUsersByNameOrSex(String name,Integer sex);
当方法有两个普通数据类型参数的时候,我们不能再像原来一样.只是简单的写参数名,而是使用以下两种方案:
方案一(不推荐使用):
使用: arg0, arg1, .....
第一个参数使用 arg0 表示
第二个参数使用 arg1 表示
第三个参数使用 arg2 表示
以此类推
第n个参数使用 arg(n-1) 表示
方案二(推荐使用):
使用: param1, param2 , .....
第一个参数是 param1
第二个参数是 param2
以此类推
第n个参数使用 paramn 表示
-->
<select id="selectUsersByNameOrSex" resultType="com.demo.pojo.User">
select `id`,`last_name`,`sex` from t_user where last_name = #{param1} or sex = #{param2}
</select>
测试的代码:
@Test
public void selectUsersByNameOrSex(){
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper userMapper = session.getMapper(UserMapper.class);
for (User bbb168 : userMapper.selectUsersByNameOrSex("bbb168", 1)) {
System.out.println(bbb168);
}
} finally {
session.close();
}
}
@Param注解命名参数
@Param注解可以对参数进行命名,然后在#{}中进行使用.
Mapper接口
/**
* 根据给定的name或sex值来查询用户信息 <br/>
* @return
*/
public List<User> selectUsersByNameOrSex(@Param("name") String name , @Param("sex") Integer sex);
Mapper.xml配置文件:
public List<User> selectUsersByNameOrSex(@Param("name") String name , @Param("sex") Integer sex);
如果有多个参数的时候,我们可以使用注解@Param对参数进行命名.然后在sql中直接使用参数名即可.
也就是说,
比如: @Param("name") String name , 那么sql语句中就可以写 #{name} <br/>
或 @Param("sex") Integer sex , sql语句中就可以写 #{sex}
也就是@Param("xxx") Integer sex , sql语句中就可以写 #{xxx}
-->
<select id="selectUsersByNameOrSex" resultType="com.demo.pojo.User">
select `id`,`last_name`,`sex` from t_user where last_name = #{name} or sex = #{sex}
</select>
测试代码:
@Test
public void selectUsersByNameOrSex(){
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper userMapper = session.getMapper(UserMapper.class);
for (User bbb168 : userMapper.selectUsersByNameOrSex("bbb168", 1)) {
System.out.println(bbb168);
}
} finally {
session.close();
}
}
Mybatis底层如何处理多个参数.
Mybatis会在源码中,把多个参数封装为Map集合使用.
12.3、传递一个Map对象作为参数
Mapper接口:
/**
* 参数map中有name和sex的值,用于做查询使用.<br/>
* @param params
* @return
*/
public List<User> selectUsersByMap(Map<String,Object> params);
Mapper.xml配置:
<!-- /**
* 参数map中有name和sex的值,用于做查询使用.<br/>
* @param params
* @return
*/
public List<User> selectUsersByMap(Map<String,Object> params);
前面我们讲过.多个参数姝时候,Mybatis会把所有参数都封装为一个Map去使用,
Map中的key就是我们在#{}中写的参数名.
那现在如果直接传进来一个map..我们只需要在#{}中写是map的key就可以取相应value的值注入到占位符中
比如:
Map<String,Object> params = new HashMap<>();
params.put("name", "bbb168");
params.put("sex", 1);
则sql中使用如下:
select `id`,`last_name`,`sex` from t_user where last_name = #{name} or sex = #{sex}
-->
<select id="selectUsersByMap" resultType="com.demo.pojo.User">
select `id`,`last_name`,`sex` from t_user where last_name = #{name} or sex = #{sex}
</select>
测试的代码:
@Test
public void selectUsersByMap(){
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper userMapper = session.getMapper(UserMapper.class);
Map<String,Object> params = new HashMap<>();
params.put("name", "bbb168");
params.put("sex", 1);
for (User user : userMapper.selectUsersByMap(params)) {
System.out.println(
user
);
}
} finally {
session.close();
}
}
12.4、一个Pojo数据类型
Mapper接口:
/**
* 保存用户
* @param user
* @return
*/
public int saveUser(User user);
Mapper.xml配置文件:
<!-- /**
* 保存用户
* @param user
* @return
*/
public int saveUser(User user);
如果参数是一个JavaBean的时候,那么我们需要在#{}中写上相应的属性名即可
-->
<insert id="saveUser" parameterType="com.demo.pojo.User">
insert into t_user(`last_name`,`sex`) values(#{lastName},#{sex})
</insert>
测试:
@Test
public void saveUser(){
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = new User(null,"hyj", 1);
userMapper.saveUser(user);
session.commit();
} finally {
session.close();
}
}
12.5、模糊查询
需求:现在要根据用户名查询用户对象。 也就是希望查询如下: select * from t_user where last_name like '%张%'
Mapper接口
/**
* 根据name做模糊查询 like "%name%"
* @param name
* @return
*/
public List<User> selectUsersLikeName(String name);
Mapper.xml配置文件:
<!-- /**
* 根据name做模糊查询 like "%name%"
* @param name
* @return
*/
public List<User> selectUsersLikeName(String name);
-->
<select id="selectUsersLikeName" resultType="com.demo.pojo.User">
select `id`,`last_name`,`sex` from t_user where last_name like #{name}
</select>
测试的代码:
@Test
public void selectUsersLikeName(){
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper userMapper = session.getMapper(UserMapper.class);
String name = "b";
for (User user : userMapper.selectUsersLikeName("%"+name+"%")) {
System.out.println(user);
}
} finally {
session.close();
}
}
public void selectUsersLikeName(){
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper userMapper = session.getMapper(UserMapper.class);
String name = "b";
for (User user : userMapper.selectUsersLikeName("%"+name+"%")) {
System.out.println(user);
}
} finally {
session.close();
}
}
12.6、#{}和${}的区别
<!-- /**
* 根据name做模糊查询 like "%name%"
* @param name
* @return
*/
public List<User> selectUsersLikeName(String name);
#{} 是占位符, 它可以解决sql注入的安全问题
${} 不是占位符,它只会把参数值输输出,然后和sql语句做字符串拼接操作
#{} 一般是用于做条件的占位符?使用
${} 一般是用于表名的使用(不用在条件中)
-->
<select id="selectUsersLikeName" resultType="com.demo.pojo.User">
select `id`,`last_name`,`sex` from t_user where last_name like '%${name}%'
</select>
#{} 是占位符?
${} 它不是占位符,它只是把参数值输出然后和sql语句做字符串拼接操作
#{} 里面写的是参数名( 一个参数的时候,可以任意写,多个参数的时候,可以使用param1,param2.或注解对参数进行命名 )
${} 里面写的是@Param的参数名
12.6.2、MySQL的字符串拼接,concat函数实现。
concat() 是mysql中提供的一个函数.它可以把多个字符串进行拼接操作
我们可以使用concat()函数解决 模糊查询中%和搜索关键字拼接的问题
<select id="selectUsersLikeName" resultType="com.demo.pojo.User">
select `id`,`last_name`,`sex` from t_user where last_name like concat('%',#{name},'%')
</select>
13、自定义结果集<resultMap></resultMap>
resultMap标签可以对查询回来的ResultSet结果集做手动映射操作.
resultSet查询回来的结果,是需要转换为JavaBean
而resultSet中的列和JavaBean中的属性是有对应关系的.
<!-- 可以将一个查询的结果和JavaBean做列和属性的映射关系
id属性设置一个唯一标识,方便引用
type指定结果集的每一行封装成为什么具体要的类型
-->
<resultMap id="resultMap1" type="com.demo.pojo.User">
<!-- 在resultmap中,我们需要指定结果集中的列和JavaBean类的属性名的对应关系 -->
<!-- id标签映射主键列和属性的对应关系
column指定列名
property指定属性名
-->
<id column="id" property ="id" />
<!-- result标签映射非主键列和属性的对应关系 -->
<result column="last_name" property ="lastName"/>
<result column="sex" property="sex"/>
</resultMap>
<!-- public User selectUserById(Integer id);
如果你的方法只有一个参数,并且是普通数据类型.只需要在#{}中写上参数名即可 <br/>
如果只有一个参数的时候,其实在#{}中可以任意书写,推荐写参数名
resultMap属性是指将我的查询结果集交给哪个ResultMap去和类做映射关系
-->
<select id="selectUserById" resultMap="resultMap1">
select `id`,`last_name`,`sex` from t_user where id = #{id}
</select>
13.1、<resultMap>的作用。
resultType属性可以指定一个具体的类型,然后mybatis会做自动映射.
resultMap标签是自定义结果集标签,它可以对查询回来的结果集做手动映射处理.
resultMap主要是用于映射复杂的Bean对象的情况
resultType属性用于简单的Bean对象的情况.
简单的Bean对象是属性只有基本数据类型的JavaBean对象
复杂的Bean对象是把属性中含有JavaBean类型的属性或List集合类型的属性的情况.
13.2、创建一对一数据库表
## 一对一数据表
## 创建锁表
create table t_lock(
`id` int primary key auto_increment,
`name` varchar(50)
);
## 创建钥匙表
create table t_key(
`id` int primary key auto_increment,
`name` varchar(50),
`lock_id` int ,
foreign key(`lock_id`) references t_lock(`id`)
);
## 插入初始化数据
insert into t_lock(`name`) values('阿里巴巴');
insert into t_lock(`name`) values('华为');
insert into t_lock(`name`) values('联想');
insert into t_key(`name`,`lock_id`) values('马云',1);
insert into t_key(`name`,`lock_id`) values('任正非',2);
insert into t_key(`name`,`lock_id`) values('柳传志',3);
13.3、创建实体对象
public class Lock {
private Integer id;
private String name;
public class Key {
private Integer id;
private String name;
private Lock lock;
Mapper接口
public interface KeyMapper {
/**
* 根据key的id值,查询出key的信息,以及它能开的锁的信息
* @param id
* @return
*/
public Key queryKeyByIdForSimple(Integer id);
}
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">
<mapper namespace="com.demo.mapper.KeyMapper">
<!--
配置resultMap对查询回来的结果进行手动映射
-->
<resultMap id="resultMap3" type="com.demo.pojo.Key">
<!--
column="id" 列名
property="id" 属性名( Key对象的id属性 )
-->
<id column="id" property="id" />
<result column="name" property="name" />
<!--
级联属性映射 <br/>
一级一级属性映射
-->
<result column="lock_id" property="lock.id" />
<result column="lock_name" property="lock.name" />
</resultMap>
<!-- /**
* 根据key的id值,查询出key的信息,以及它能开的锁的信息
* @param id
* @return
*/
public Key queryKeyByIdForSimple(Integer id);-->
<select id="queryKeyByIdForSimple" resultMap="resultMap3">
select
t_key.*,
t_lock.name lock_name
from
t_key left join t_lock
on
t_key.lock_id = t_lock.id
where
t_key.id = #{id}
</select>
</mapper>
测试的代码:
public class KeyMapperTest {
static SqlSessionFactory sqlSessionFactory;
@BeforeClass
public static void init() throws IOException {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(
Resources.getResourceAsStream("mybatis-config.xml")
);
}
@Test
public void queryKeyByIdForSimple() {
SqlSession session = sqlSessionFactory.openSession();
try {
KeyMapper mapper = session.getMapper(KeyMapper.class);
Key key = mapper.queryKeyByIdForSimple(1);
System.out.println(key);
} finally {
session.close();
}
}
}
13.4.2、<association /> 嵌套结果集映射配置
association 标签专门用来映射子对象.
1 通过调用一个查询得到子对象
2 直接将查询回来的结果直接进行映射( 一次性把所有数据都查询回来 )
<!--
配置resultMap对查询回来的结果进行手动映射
-->
<resultMap id="resultMap3" type="com.demo.pojo.Key">
<!--
column="id" 列名
property="id" 属性名( Key对象的id属性 )
-->
<id column="id" property="id" />
<result column="name" property="name" />
<!--
级联属性映射 <br/>
一级一级属性映射
<result column="lock_id" property="lock.id" />
<result column="lock_name" property="lock.name" />-->
<!--
association 也可以把一次性查询回来的子对象的数据进行映射
property属性设置子对象的属性名
javaType属性设置子对象的具体全类名
-->
<association property="lock" javaType="com.demo.pojo.Lock">
<result column="lock_id" property="id" />
<result column="lock_name" property="name" />
</association>
</resultMap>
13.4.3、<association /> 定义分步查询
LockMapper接口:
public interface LockMapper {
/**
* 只查lock的信息(不常用信息)
* @param lockId
* @return
*/
public Lock queryLockByLockId(Integer lockId);
}
LockMapper.xml配置文件:
<!-- /**
* 只查lock的信息(不常用信息)
* @param lockId
* @return
*/
public Lock queryLockByLockId(Integer lockId);-->
<select id="queryLockByLockId" resultType="com.demo.pojo.Lock">
select `id`,`name` from t_lock where id = #{lock_id}
</select>
KeyMapper接口
/**
* 分两次查询Key信息,这里只查key ( 常用列信息 )<br/>
* @return
*/
public Key queryKeyForTwoStepByKeyId(Integer keyId);
KeyMapper.xml配置文件:
<resultMap id="queryKeyForTwoStepByKeyIdResultMap"
type="com.demo.pojo.Key">
<id column="id" property="id" />
<result column="name" property="name" />
<!--
association标签专门用来映射复杂的子对象的属性
property表示子对象的属性名
javaType表示对象的具体类型
select属性表示调用哪个select查询
column表示将结果集中哪个列做为参数给调用的select使用
-->
<association property="lock" javaType="com.demo.pojo.Lock" column="lock_id"
select="com.demo.mapper.LockMapper.queryLockByLockId"
/>
</resultMap>
<!-- /**
* 分两次查询Key信息,这里只查key ( 常用列信息 )<br/>
* @return
*/
public Key queryKeyForTwoStepByKeyId(Integer keyId);-->
<select id="queryKeyForTwoStepByKeyId"
resultMap="queryKeyForTwoStepByKeyIdResultMap">
select `id`,`name`,`lock_id` from t_key where id = #{keyId}
</select>
测试的代码:
@Test
public void queryKeyForTwoStepByKeyId(){
SqlSession session = sqlSessionFactory.openSession();
try {
KeyMapper mapper = session.getMapper(KeyMapper.class);
Key key = mapper.queryKeyForTwoStepByKeyId(1);
System.out.println(key);
} finally {
session.close();
}
}
13.5、延迟加载
延迟加载在一定程序上可以减少很多没有必要的查询。给数据库服务器提升性能上的优化。
要启用延迟加载,需要在mybatis-config.xml配置文件中,添加如下两个全局的settings配置。
<!-- 打开延迟加载的开关 -->
<setting name="lazyLoadingEnabled" value="true" />
<!-- 将积极加载改为消极加载 按需加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
13.6、多对一、一对多的使用示例
13.6.1、创建一对多数据库
## 一对多数据表
## 创建班级表
create table t_clazz(
`id` int primary key auto_increment,
`name` varchar(50)
);
## 插入班级信息
insert into t_clazz(`name`) values('javaEE');
insert into t_clazz(`name`) values('C++');
insert into t_clazz(`name`) values('H5');
insert into t_clazz(`name`) values('LUA');
## 创建学生表
create table t_student(
`id` int primary key auto_increment,
`name` varchar(50),
`clazz_id` int,
foreign key(`clazz_id`) references t_clazz(`id`)
);
## 插入班级信息
insert into t_student(`name`,`clazz_id`) values('javaEE_1',1);
insert into t_student(`name`,`clazz_id`) values('javaEE_2',1);
insert into t_student(`name`,`clazz_id`) values('javaEE_3',1);
insert into t_student(`name`,`clazz_id`) values('C++_1',2);
insert into t_student(`name`,`clazz_id`) values('C++_2',2);
insert into t_student(`name`,`clazz_id`) values('H5_1',3);
13.6.2、<collection/> 一对多,立即加载
public class Student {
private Integer id;
private String name;
public class Clazz {
private Integer id;
private String name;
private List<Student> stus;
ClazzMapper接口
public interface ClazzMapper {
/**
* 一次性查询出班级和班级的所有学生信息
* @param clazzId
* @return
*/
public Clazz selectClazzByClazzIdForSimple(Integer clazzId);
}
ClazzMapper.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">
<mapper namespace="com.demo.mapper.ClazzMapper">
<resultMap id="selectClazzByClazzIdForSimpleResultMap"
type="com.demo.pojo.Clazz">
<!--id是主键列,使用id标签-->
<id column="id" property="id" />
<result column="name" property="name" />
<!--
collection标签用于配置集合属性
property属性设置集合的属性名
ofType设置集合中每个对象的具体类型
-->
<collection property="stus" ofType="com.demo.pojo.Student">
<!-- 因为对学生而言 stu_id 是学生的主键 -->
<id column="stu_id" property="id" />
<result column="stu_name" property="name" />
</collection>
</resultMap>
<!-- /**
* 一次性查询出班级和班级的所有学生信息
* @param clazzId
* @return
*/
public Clazz selectClazzByClazzIdForSimple(Integer clazzId);-->
<select id="selectClazzByClazzIdForSimple"
resultMap="selectClazzByClazzIdForSimpleResultMap">
select
t_clazz.*,
t_student.id stu_id,
t_student.name stu_name
from
t_clazz left join t_student
on
t_clazz.id = t_student.clazz_id
where
t_clazz.id = #{clazzId}
</select>
</mapper>
测试代码:
@Test
public void selectClazzByClazzIdForSimple() {
SqlSession session = sqlSessionFactory.openSession();
try {
ClazzMapper clazzMapper = session.getMapper(ClazzMapper.class);
Clazz clazz = clazzMapper.selectClazzByClazzIdForSimple(1);
System.out.println(clazz);
} finally {
session.close();
}
}
13.6.3、一对多,分步查询,赖加载
StudentMapper接口
public interface StudentMapper {
/**
* 专门查询学生
* @param clazzId
* @return
*/
public List<Student> queryStudentsByClazzId(Integer clazzId);
}
StudentMapper.xml配置文件
<mapper namespace="com.demo.mapper.StudentMapper">
<!-- /**
* 专门查询学生
* @param clazzId
* @return
*/
public List<Student> queryStudentsByClazzId(Integer clazzId);-->
<select id="queryStudentsByClazzId" resultType="com.demo.pojo.Student">
select `id`,`name` from t_student where clazz_id = #{clazzId}
</select>
</mapper>
ClazzMapper接口添加的方法
/**
* 分两次查,一次查班级,一次查学生(如果学生不用,就不查)
* @param clazzId
* @return
*/
public Clazz selectClazzByClazzIdForTwoStep(Integer clazzId);
ClazzMapper.xml添加的配置:
<resultMap id="selectClazzByClazzIdForTwoStepResultMap"
type="com.demo.pojo.Clazz">
<id column="id" property="id" />
<result column="name" property="name" />
<!--
集合始终是使用collection标签来映射
collection标签可以把一次性查询回来的数据都封装为集合对象
也可以通过调用一个查询得到集合对象
property表示集合的属性名
select 表示调用哪个查询
column表示把结果集中哪个列的值做为调用的查询的参数
-->
<collection property="stus" column="id"
select="com.demo.mapper.StudentMapper.queryStudentsByClazzId"
/>
</resultMap>
<!-- /**
* 分两次查,一次查班级,一次查学生(如果学生不用,就不查)
* @param clazzId
* @return
*/
public Clazz selectClazzByClazzIdForTwoStep(Integer clazzId);-->
<select id="selectClazzByClazzIdForTwoStep"
resultMap="selectClazzByClazzIdForTwoStepResultMap">
select `id`,`name` from t_clazz where id = #{clazzId}
</select>
测试的代码:
@Test
public void selectClazzByClazzIdForTwoStep() throws InterruptedException {
SqlSession session = sqlSessionFactory.openSession();
try {
ClazzMapper clazzMapper = session.getMapper(ClazzMapper.class);
Clazz clazz = clazzMapper.selectClazzByClazzIdForTwoStep(1);
System.out.println(clazz.getName());
Thread.sleep(5000);
System.out.println( clazz.getStus() );
} finally {
session.close();
}
}
多列值的传递
StudnetMapper接口:
/**
* 根据指定班级id查询学生.并且学生的姓名,还要做模糊查询<br/>
* @param clazzId
* @param name
* @return
*/
public List<Student> queryStudentsByClazzIdAndLikeName(
@Param("clazzId") Integer clazzId,
@Param("stu_name") String name);
StudnetMapper.xml配置文件:
<!-- /**
* 根据指定班级id查询学生.并且学生的姓名,还要做模糊查询<br/>
* @param clazzId
* @param name
* @return
*/
public List<Student> queryStudentsByClazzIdAndLikeName(
@Param("clazzId") Integer clazzId,
@Param("stu_name") String name);
-->
<select id="queryStudentsByClazzIdAndLikeName"
resultType="com.demo.pojo.Student">
select
`id`,`name`
from
t_student
where
clazz_id = #{clazzId}
and
name like concat('%',#{stu_name},'%')
</select>
ClazzMapper.xml配置文件
<resultMap id="selectClazzByClazzIdForTwoStepResultMap"
type="com.demo.pojo.Clazz">
<id column="id" property="id" />
<result column="name" property="name" />
<!--
集合始终是使用collection标签来映射
collection标签可以把一次性查询回来的数据都封装为集合对象
也可以通过调用一个查询得到集合对象
property表示集合的属性名
select 表示调用哪个查询
column表示把结果集中哪个列的值做为调用的查询的参数
public List<Student> queryStudentsByClazzIdAndLikeName(
@Param("clazzId") Integer clazzId,
@Param("stu_name") String name);
多列传值的格式如下: {参数名=列名,参数名=列名}
{ clazzId=id,stu_name=name }
-->
<collection property="stus" column="{clazzId=id,stu_name=name}"
select="com.demo.mapper.StudentMapper.queryStudentsByClazzIdAndLikeName"
/>
</resultMap>
14、动态SQL语句
动态的sql语句是指,mybatis根据参数值的不同.动态的改变sql语句的内容.
准备工作:
public class User {
private int id;
private String lastName;
private int sex;
14.1、if 语句
说明: if语句,可以动态的根据你的值来决定,是否需要动态的添加查询条件。
mapper接口
public interface UserMapper {
/**
* 根据用户lastName和sex来查询用户信息 <br/>
* 1 性别的有效值是0和1 , 1表示男,0表示女.,如果性别值无效,就不加入到查询条件中 <br/>
* 2 lastName的值如果是null,也不加入到查询条件中 <br/>
* @param user
* @return
*/
public List<User> selectUsersByNameAndSex(User user);
}
mapper.xml配置文件:
<!-- /**
* 根据用户lastName和sex来查询用户信息
* @param user
* @return
*/
public List<User> selectUsersByNameAndSex(User user);-->
<select id="selectUsersByNameAndSex" resultType="com.demo.pojo.User"
parameterType="com.demo.pojo.User">
select
`id`,`last_name` lastName,`sex`
from
t_user
where
<!-- 如果lastName不等于null,则查询条件添加last_name的模糊查询 -->
<if test="lastName != null">
last_name like concat('%',#{lastName},'%')
and
</if>
<!-- sex如果值有效,则添加入到查询条件中 -->
<if test="sex == 0 || sex == 1">
sex = #{sex}
</if>
</select>
测试的代码:
@Test
public void selectUsersByNameAndSex() {
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
for (User user : mapper.selectUsersByNameAndSex(new User(null, null, 1))) {
System.out.println(user);
}
} finally {
session.close();
}
}
14.2、where 语句
说明: where语句,
1 可以帮我们在多个动态语句中,有效的去掉前面的多余的and 或 or 之类的多余关键字,
2 还可以判断是否有条件,如果有就添加where关键字
<!-- /**
* 根据用户lastName和sex来查询用户信息
* @param user
* @return
*/
public List<User> selectUsersByNameAndSex(User user);-->
<select id="selectUsersByNameAndSex" resultType="com.demo.pojo.User"
parameterType="com.demo.pojo.User">
select
`id`,`last_name` lastName,`sex`
from
t_user
<!-- where动态语句
1 可以帮我们在多个动态语句中,有效的去掉前面的多余的 and 或 or 之类的多余关键字,
2 还可以判断是否有条件,如果有就添加where关键字
-->
<where>
<!-- 如果lastName不等于null,则查询条件添加last_name的模糊查询 -->
<if test="lastName != null">
last_name like concat('%',#{lastName},'%')
</if>
<!-- sex如果值有效,则添加入到查询条件中 -->
<if test="sex == 0 || sex == 1">
and
sex = #{sex}
</if>
</where>
14.3、trim语句
说明: trim 可以动态在包含的语句前面和后面添加内容 或 删除指定内容。
prefix 前面添加内容( 如果没有包含的内容,不添加 )
suffix 后面添加内容( 如果没有包含的内容,不添加 )
suffixOverrides 去掉的后面内容
prefixOverrides 去掉的前面内容
<!-- /**
* 根据用户lastName和sex来查询用户信息
* @param user
* @return
*/
public List<User> selectUsersByNameAndSex(User user);-->
<select id="selectUsersByNameAndSex" resultType="com.demo.pojo.User"
parameterType="com.demo.pojo.User">
select
`id`,`last_name` lastName,`sex`
from
t_user
<!--
trim 语句,可以在包含的内容前面和后面 添加添加或删除指定内容 ( if语句先执行,执行完再执行trim )
prefix 前面添加内容( 如果没有包含的内容,不添加 )
suffix 后面添加内容( 如果没有包含的内容,不添加 )
suffixOverrides 去掉的后面内容
prefixOverrides 去掉的前面内容
-->
<trim suffixOverrides="and" prefixOverrides="and" prefix="where">
<!-- 如果lastName不等于null,则查询条件添加last_name的模糊查询 -->
<if test="lastName != null">
last_name like concat('%',#{lastName},'%')
</if>
<!-- sex如果值有效,则添加入到查询条件中 -->
<if test="sex == 0 || sex == 1">
and
sex = #{sex}
</if>
</trim>
</select>
14.4、choose( when , otherwise )语句
说明:choose when otherwise 可以执行多路选择判断,但是只会有一个分支会被执行。
类似switch case default语句
Mapper接口
/**
* 1 如果lastName属性值有效,则只按照lastName属性做模糊查询 <br/>
* 2 如果lastName无效,sex有效,则只按照sex进行查询<br/>
* 3 如果lastName和sex都无效,则使用自定义查询条件
* @param user
* @return
*/
public List<User> selectUsersByUserChooseWhenOtherwise(User user);
Mapper.xml配置文件
<!-- /**
* 1 如果lastName属性值有效,则只按照lastName属性做模糊查询 <br/>
* 2 如果lastName无效,sex有效,则只按照sex进行查询<br/>
* 3 如果lastName和sex都无效,则使用自定义查询条件
* @param user
* @return
*/
public List<User> selectUsersByUserChooseWhenOtherwise(User user);-->
<select id="selectUsersByUserChooseWhenOtherwise"
resultType="com.demo.pojo.User"
parameterType="com.demo.pojo.User">
select
`id`,`last_name` lastName,`sex`
from
t_user
<where>
<choose>
<!-- 如果lastName属性值不等于null就做模糊查询 -->
<when test="lastName != null">
last_name like concat('%',#{lastName},'%')
</when>
<!-- 如果lastName值无效,sex有效,按sex查询 -->
<when test="sex == 0 or sex == 1">
sex = #{sex}
</when>
<!-- 如果lastName无效,sex也无效,使用自定义查询条件 -->
<otherwise>
1 = 1
</otherwise>
</choose>
</where>
</select>
测试代码:
@Test
public void selectUsersByUserChooseWhenOtherwise() {
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
for (User user : mapper.selectUsersByUserChooseWhenOtherwise(new User(null, null, 10))) {
System.out.println(user);
}
} finally {
session.close();
}
}
14.4、set语句
set语句可以删除更新字段后的逗号
Mapper接口
/**
* 如果lastName或sex值无效就不更新
* @param user
* @return
*/
public int updateUser(User user);
Mapper.xml配置文件:
<update id="updateUser" parameterType="com.demo.pojo.User">
update t_user
<!-- set可以去掉包含内容后面的逗号,如果有包含的内容还会添加set关键字 -->
<set>
<if test="lastName != null">
last_name = #{lastName} ,
</if>
<if test="sex == 0 || sex == 1">
sex = #{sex}
</if>
</set>
where id = #{id}
</update>
14.5、foreach语句
foreach 语句用来做遍历操作.它可以遍历实现多个in条件的查询,也可以实现批量插入
select * from 表名 where id in ( xx,xxx,xx )
Mapper接口
/**
* 执行where id in (xx,xx,xx) 查询
* @param ids
* @return
*/
public List<User> selectUsersByIds( List<Integer> ids);
Mapper.xml配置文件
<!-- /**
* 执行where id in (xx,xx,xx) 查询
* @param ids
* @return
*/
public List<User> selectUsersByIds(List<Integer> ids);-->
<select id="selectUsersByIds" resultType="com.demo.pojo.User">
select
`id`,`last_name` lastName,`sex`
from
t_user
<where>
<!-- foreach标签用于遍历操作
collection遍历的数据源
item 是当前遍历的数据
separator是每个遍历元素中的分隔符
open 是在遍历内容前面添加
close 是在遍历内容后面添加
-->
<foreach open="id in (" close=")" collection="list" item="id" separator=",">
#{id}
</foreach>
</where>
</select>
测试代码:
@Test
public void selectUsersByIds(){
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
List<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(2);
ids.add(3);
for (User user : mapper.selectUsersByIds(ids)) {
System.out.println(user);
}
} finally {
session.close();
}
}
insert into 表名(列1,列2) values(值1,值2) , (值1,值2) , (值1,值2) ......
Mapper接口
/**
* 批量插入
* @param users
* @return
*/
public int insertUsers( @Param("users") List<User> users );
Mapper.xml配置文件
<!-- /**
* 批量插入
* @param users
* @return
*/
public int insertUsers( @Param("users") List<User> users );
-->
<insert id="insertUsers">
insert into
t_user(`last_name`,`sex`)
values
<foreach collection="users" item="user" separator=",">
(#{user.lastName},#{user.sex})
</foreach>
</insert>
测试代码:
@Test
public void insertUsers(){
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> users = new ArrayList<>();
users.add(new User(null,"11111", 0));
users.add(new User(null,"22222", 1));
users.add(new User(null,"33333", 1));
mapper.insertUsers(users);
session.commit();
} finally {
session.close();
}
}
14.6、sql片段
sql片段是指把多个sql语句中相同的内容进行抽取为sql片段,在需要使用的地方进行引入即可.
<!--抽取sql片段
Id是唯一的标识-->
<sql id=””
15、mybatis缓存
缓存:按动词解释是把经常需要访问的数据,预先保存到高速缓冲区中,方便用户高速访问.
按名词解释.缓存指的是,提前保存起来方便用户高速访问的数据叫缓存.
一级缓存: 同一个SqlSession对象
二级缓存: 同一个SqlSessionFactory对象
缓存的目的就一个,就是为了提高访问速度.
15.1、mybatis的一级缓存的示例
@Test
public void selectUserById() {
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectUserById(1);
System.out.println(user);
User user2 = mapper.selectUserById(1);
System.out.println(user2);
} finally {
session.close();
}
}
15.1.2、一级缓存的管理
缓存失效的四种情况:
- 不在同一个SqlSession对象中
public void queryOne(){
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectUserById(1);
System.out.println(user);
} finally {
session.close();
}
}
@Test
// 1.不在同一个SqlSession对象中
public void firstLevelCacheFail1(){
queryOne();
queryOne();
}
- 执行语句的参数不同。缓存中也不存在数据。
@Test
//2.执行语句的参数不同。缓存中也不存在数据。
public void firstLevelCacheFail2(){
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectUserById(1);
System.out.println(user);
User user2 = mapper.selectUserById(2);
System.out.println(user2);
} finally {
session.close();
}
}
- 执行增,删,改,语句,会清空掉缓存
@Test
// 3.执行增,删,改,语句,会清空掉缓存
public void firstLevelCacheFail3() {
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectUserById(1);
System.out.println(user);
mapper.updateUser(new User(3, "xxx", 0));
User user2 = mapper.selectUserById(1);
System.out.println(user2);
session.commit();
} finally {
session.close();
}
}
- 手动清空缓存数据
@Test
//4.手动清空缓存数据
public void firstLevelCacheFail4() {
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectUserById(1);
System.out.println(user);
session.clearCache();// clear清空,cache缓存,
User user2 = mapper.selectUserById(1);
System.out.println(user2);
} finally {
session.close();
}
}
15.2、mybatis的二级缓存
二级缓存的图解示意
一级缓存强制开始使用.
二级缓存的使用:
myBatis的二级缓存默认是不开启的。
1 我们需要在mybatis的核心配置文件中配置setting选项
<setting name="cacheEnabled" value="true"/>
2 在Mapper.xml的配置文件中加入cache标签。启用二级缓存
3 需要被二级缓存的对象必须要实现java的序列化接口。
15.2.1、二级缓存的演示
public void queryOne() {
SqlSession session = sqlSessionFactory.openSession();
try {
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectUserById(1);
System.out.println(user);
} finally {
session.close();
}
}
@Test
public void testSecondLevelCache(){
queryOne();
queryOne();
}
15.2.2、useCache="false"的演示和说明
useCache属性它是select标签中的属性,表示是否将查询的结果保存到二级缓存中.默认是true.保存到二级缓存中
<!--
useCache="false" 表示不将查询的结果保存到二级缓存中
-->
<select id="selectUserById" resultType="com.demo.pojo.User" useCache="false">
select `id`,`last_name` lastName,`sex` from t_user where id = #{id}
</select>
15.2.3、flushCache="false"的演示和说明
是在insert , delete , update 标签中的属性,它表示执行写操作的时候,是否清空二级缓存.
默认值是true,表示执行insert delete update 语句就会清空缓存.
<!--
flushCache="false"表示设置执行当前update操作是否清空缓存
-->
<update id="updateUser" flushCache="false" parameterType="com.demo.pojo.User">
update t_user set last_name=#{lastName},sex=#{sex} where id = #{id}
</update>
自定义二级缓存
如果要自定义mybatis的二级缓存,需要实现Cache接口.
一级缓存默认实现类 : org.apache.ibatis.cache.impl.PerpetualCache
自定义二级缓存步骤如下:
1 编写一个类去实现Cache接口
2 到mapper.xml配置文件中,修改<cache type=”” />
使用Redis做为mybatis的二级缓存.
public class MySecondCache implements Cache {
private final String id;
private Map<Object, Object> cache = new HashMap();
public MySecondCache(String id) {
this.id = id;
}
public String getId() {
return this.id;
}
public int getSize() {
return this.cache.size();
}
public void putObject(Object key, Object value) {
System.out.println(" 往二级缓存中保存数据 ");
this.cache.put(key, value);
}
public Object getObject(Object key) {
System.out.println(" 从二级缓存中获取数据 ");
return this.cache.get(key);
}
public Object removeObject(Object key) {
return this.cache.remove(key);
}
public void clear() {
this.cache.clear();
}
public ReadWriteLock getReadWriteLock() {
return null;
}
public boolean equals(Object o) {
if (this.getId() == null) {
throw new CacheException("Cache instances require an ID.");
} else if (this == o) {
return true;
} else if (!(o instanceof Cache)) {
return false;
} else {
Cache otherCache = (Cache)o;
return this.getId().equals(otherCache.getId());
}
}
public int hashCode() {
if (this.getId() == null) {
throw new CacheException("Cache instances require an ID.");
} else {
return this.getId().hashCode();
}
}
}
<!-- 使用自定义二级缓存 -->
<cache type="com.demo.cache.MySecondCache"></cache>
16、缓存的使用顺序说明( 了解 ):
1、当我们执行一个查询语句的时候。mybatis会先去二级缓存中查询数据。
2 二级缓存中没有。就到一级缓存中查找。
3 如果二级缓存和一级缓存都没有。就发sql语句到数据库中去查询。
4、查询出来之后马上把数据保存到一级缓存中。
5、当SqlSession关闭的时候,会把一级缓存中的数据保存到二级缓存中。
17、mybatis 逆向工程
MyBatis逆向工程,简称MBG。是一个专门为MyBatis框架使用者定制的代码生成器。可以快速的根据表生成对应的映射文件,接口,以及Bean类对象。
在Mybatis中,是一个可以自动对单表生成的增,删,改,查代码的插件。
叫 mybatis-generator-core-1.3.2。
它可以帮我们对比数据库表之后,生成大量的这个基础代码。
这些基础代码有:
- 数据库表对应的javaBean对象
- 这些javaBean对象对应的Mapper接口
- 这些Mapper接口对应的配置文件
<!-- 去掉全部的注释 -->
<commentGenerator>
<property name="suppressAllComments" value="true" />
</commentGenerator>
17.1、准备数据库表
create database mbg;
use mbg;
create table t_user(
`id` int primary key auto_increment,
`username` varchar(30) not null unique,
`password` varchar(40) not null,
`email` varchar(50)
);
insert into t_user(`username`,`password`,`email`) values('admin','admin','admin@demo.com');
insert into t_user(`username`,`password`,`email`) values('wzg168','123456','admin@demo.com');
insert into t_user(`username`,`password`,`email`) values('admin168','123456','admin@demo.com');
insert into t_user(`username`,`password`,`email`) values('lisi','123456','admin@demo.com');
insert into t_user(`username`,`password`,`email`) values('wangwu','123456','admin@demo.com');
create table t_book(
`id` int primary key auto_increment,
`name` varchar(50),
`author` varchar(50),
`price` decimal(11,2),
`sales` int,
`stock` int
);
## 插入初始化测试数据
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` )
values(null , 'java从入门到放弃' , '国哥' , 80 , 9999 , 9);
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` )
values(null , '数据结构与算法' , '严敏君' , 78.5 , 6 , 13);
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` )
values(null , '怎样拐跑别人的媳妇' , '龙伍' , 68, 99999 , 52);
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` )
values(null , '木虚肉盖饭' , '小胖' , 16, 1000 , 50);
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` )
values(null , 'C++编程思想' , '刚哥' , 45.5 , 14 , 95);
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` )
values(null , '蛋炒饭' , '周星星' , 9.9, 12 , 53);
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` )
values(null , '赌神' , '龙伍' , 66.5, 125 , 535);
select * from t_user;
select * from t_book;
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="DB2Tables" targetRuntime="MyBatis3">
<!-- 去掉全部的注释 -->
<commentGenerator>
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--
修改数据库连接的属性信息
-->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mbg"
userId="root"
password="root">
</jdbcConnection>
<javaTypeResolver >
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!--
javaModelGenerator标签是JavaBean的生成配置
targetPackage 生成的类的包名
targetProject 生成的类在哪个模块目录下
-->
<javaModelGenerator targetPackage="com.demo.pojo"
targetProject=".\08-mybatis-mbg\src">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!--
sqlMapGenerator标签是生成mapper.xml配置文件的
targetPackage 生成的配置文件在哪个包名下
targetProject 生成的文件在哪个模块目录下
-->
<sqlMapGenerator targetPackage="com.demo.mapper"
targetProject=".\08-mybatis-mbg\src">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!--
javaClientGenerator标签配置生成的mapper接口信息
targetPackage 包名
targetProject 哪个模块目录下
-->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.demo.mapper"
targetProject=".\08-mybatis-mbg\src">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!--
一个table标签表示一个表
tableName表示表名
domainObjectName表示生成的类名
-->
<table tableName="t_user" domainObjectName="User" />
<table tableName="t_book" domainObjectName="Book" />
</context>
</generatorConfiguration>
逆向工程运行的代码:
public class MbgRunner {
public static void main(String[] args) throws IOException, XMLParserException, InvalidConfigurationException, SQLException, InterruptedException {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("08-mybatis-mbg/mbg.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
}
}
生成的豪华版本的查询条件方法使用说明:
豪华版的测试代码
package com.demo.mapper.test;
import com.demo.mapper.BookMapper;
import com.demo.pojo.Book;
import com.demo.pojo.BookExample;
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.BeforeClass;
import org.junit.Test;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
public class BookMapperTest {
static SqlSessionFactory sqlSessionFactory;
@BeforeClass
public static void init() throws IOException {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(
Resources.getResourceAsStream("mybatis-config.xml")
);
}
@Test
public void countByExample() {
SqlSession session = sqlSessionFactory.openSession();
try {
BookMapper mapper = session.getMapper(BookMapper.class);
BookExample bookExample = new BookExample();
//创建一个查询条件
BookExample.Criteria criteria = bookExample.createCriteria();
// author=国哥
criteria.andAuthorEqualTo("国哥");
// 价格大于100
criteria.andPriceGreaterThan(new BigDecimal(100));
BookExample.Criteria or = bookExample.or();
// 查询 id in(xx,xx,xx);
List<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(2);
ids.add(3);
or.andIdIn(ids);
// count打头的方法,表示用于执行select count() 表名 where 查询条件 统计数量
// 参数就是查询的条件
// 如果参数为null,表示全部
int count = mapper.countByExample(bookExample);
System.out.println(count);
session.commit();
} finally {
session.close();
}
}
@Test
public void deleteByExample() {
SqlSession session = sqlSessionFactory.openSession();
try {
BookMapper mapper = session.getMapper(BookMapper.class);
// 销量大于100 或 库存大于100
BookExample bookExample = new BookExample();
BookExample.Criteria criteria = bookExample.createCriteria();
criteria.andSalesGreaterThan(100);
// or 关系的条件
BookExample.Criteria or = bookExample.or();
or.andStockGreaterThan(100);
// ByExample 表示按条件操作
// 如果条件是null,表示全部
mapper.deleteByExample(bookExample);
session.commit();
} finally {
session.close();
}
}
@Test
public void deleteByPrimaryKey() {
SqlSession session = sqlSessionFactory.openSession();
try {
BookMapper mapper = session.getMapper(BookMapper.class);
// delete , update ,select , insert 表示操作
// By 按什么什么条件
// ByExample 表示按条件操作
// ByPrimaryKey 按主键
mapper.deleteByPrimaryKey(1);
session.commit();
} finally {
session.close();
}
}
@Test
public void insert() {
SqlSession session = sqlSessionFactory.openSession();
try {
BookMapper mapper = session.getMapper(BookMapper.class);
mapper.insert(
new Book(null, "富婆通讯录",
"灿侨",new BigDecimal("9999999"),1234 ,12341234));
session.commit();
} finally {
session.close();
}
}
@Test
public void insertSelective() {
SqlSession session = sqlSessionFactory.openSession();
try {
BookMapper mapper = session.getMapper(BookMapper.class);
Book book = new Book(null,"锅从天上来",
"史棋文", null, null,1234);
// 只要方法名中带有Selective,就表示会忽略值为null的列
mapper.insertSelective(book); // 忽略null值的列
mapper.insert(book); // 不忽略null值的列
session.commit();
} finally {
session.close();
}
}
@Test
public void selectByExample() {
SqlSession session = sqlSessionFactory.openSession();
try {
BookMapper mapper = session.getMapper(BookMapper.class);
BookExample bookExample = new BookExample();
BookExample.Criteria criteria = bookExample.createCriteria();
// 作者是周星星
criteria.andAuthorEqualTo("周星星");
BookExample.Criteria or = bookExample.or();
// 价格大于10块
or.andPriceGreaterThan(new BigDecimal(10));
BookExample.Criteria or1 = bookExample.or();
// 名字带算法
or1.andNameLike("%" + "算法" + "%");
// 添加排序
bookExample.setOrderByClause( " stock desc " );
// select 是查询操作
// ByExample 按条件来查询
List<Book> books = mapper.selectByExample(bookExample);
for (Book book : books) {
System.out.println(book);
}
session.commit();
} finally {
session.close();
}
}
@Test
public void selectByPrimaryKey() {
SqlSession session = sqlSessionFactory.openSession();
try {
BookMapper mapper = session.getMapper(BookMapper.class);
System.out.println(mapper.selectByPrimaryKey(4));
session.commit();
} finally {
session.close();
}
}
@Test
public void updateByExampleSelective() {
SqlSession session = sqlSessionFactory.openSession();
try {
BookMapper mapper = session.getMapper(BookMapper.class);
/**
* 第一个参数是,更新的值<br/>
* 第二个参数是,更新的条件<br/>
*/
Book book = new Book(4,"红烧肉",null,
new BigDecimal(10),10,10);
BookExample bookExample = new BookExample();
bookExample.createCriteria().andIdEqualTo(4);
mapper.updateByExample(book,bookExample); //不忽略空列
mapper.updateByExampleSelective(book,bookExample);//忽略空列的操作
session.commit();
} finally {
session.close();
}
}
@Test
public void updateByPrimaryKeySelective() {
SqlSession session = sqlSessionFactory.openSession();
try {
BookMapper mapper = session.getMapper(BookMapper.class);
session.commit();
} finally {
session.close();
}
}
@Test
public void updateByPrimaryKey() {
SqlSession session = sqlSessionFactory.openSession();
try {
BookMapper mapper = session.getMapper(BookMapper.class);
// mapper.updateByPrimaryKey()//跟CRUD一样
session.commit();
} finally {
session.close();
}
}
}