MyBatis基本入门篇
No.1 基础
框架核心
1、 mybatis配置文件,包括Mybatis全局配置文件和Mybatis映射文件,其中全局配置文件配置了数据源、事务等信息;映射文件配置了SQL执行相关的 信息。
站在用户的角度思考问题,与客户深入沟通,找到水城网站设计与水城网站推广的解决方案,凭借多年的经验,让设计与互联网技术结合,创造个性化、用户体验好的作品,建站类型包括:网站设计、成都网站制作、企业官网、英文网站、手机端网站、网站推广、国际域名空间、网站空间、企业邮箱。业务覆盖水城地区。
2、 mybatis通过读取配置文件信息(全局配置文件和映射文件),构造出SqlSessionFactory,即会话工厂。
3、 通过SqlSessionFactory,可以创建SqlSession即会话。Mybatis是通过SqlSession来操作数据库的。
4、 SqlSession本身不能直接操作数据库,它是通过底层的Executor执行器接口来操作数据库的。Executor接口有两个实现类,一个是普通执行器,一个是缓存执行器(默认)。
5、 Executor执行器要处理的SQL信息是封装到一个底层对象MappedStatement中。该对象包括:SQL语句、输入参数映射信息、输出结果集映射信息。其中输入参数和输出结果的映射类型包括HashMap集合对象、POJO对象类型。
MyBatis 入门
引入 jar
mybatis-3.2.7.jar
MySQL-connector-java-5.1.7-bin.jar
创建实体
public class User {
private int id;
private String name;
private String dept;
private String phone;
private String website;
// 省略 get set 方法
}
创建配置
创建映射
测试
public class Main {
private static SqlSessionFactory sqlSessionFactory;
private static SqlSession sqlSession;
private static Reader reader;
static {
try {
reader = Resources.getResourceAsReader("config/mybatis-config.xml");
} catch (IOException e) {
e.printStackTrace();
}
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
sqlSession = sqlSessionFactory.openSession();
}
@Test
public void test {
User user = sqlSession.selectOne("getUserById", 1);
System.out.println(user);
}
}
CURD
创建实体(同上)
创建 IUser
public interface IUser {
public List getUserList();
public void insertUser(User user);
public void updateUser(User user);
public void deleteUser(int userId);
public User getUser(int id);
}
创建配置(同上)
创建映射
No.2 关联查询
一对多
创建实体
User
public class User implements Serializable {
private int id;
private String username;
private String mobile;
private List posts;
// 省略 get 和 set
// 重写 toString
}
Post
public class Post implements Serializable {
private int id;
private User user;
private String title;
private String content;
// 省略 get 和 set
// 重写 toString
}
创建配置(同上)
创建映射
多对一
创建实体(同上)
创建配置(同上)
创建映射
多对多
创建实体
OrderItem
public class OrderItem {
private int id;
private int number;
private Order order;
private Product product;
// 省略 get 和 set
}
Order
public class Order {
private int id;
private String code;
List orderItems;
// 省略 get 和 set
}
创建映射
OrderItem.xml
insert into order_item_
values(null,#{order.id},#{product.id},#{number})
delete from order_item_
where oid = #{order.id} and pid = #{product.id}
Order.xml
Product.xml
No.3 动态 SQL
if
如果没有传参数 name,那么就查询所有,如果有 name 参数,那么就进行模糊查询。
where
如果任何条件都不成立,那么在 sql 中不会出现 where,如果有一个条件成立,则 sql 中会去掉 and、or。
set
效果与 where 类似,用于 update
update product_
name=#{name},
price=#{price}
where id=#{id}
trim
自定义标签
choose
实现 if/else 的效果
foreach
bind
No.4 settings
设置参数 | 描述 | 有效值 | 默认值 |
---|---|---|---|
cacheEnabled | 全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存。 | true | false | true |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchType 属性来覆盖该项的开关状态。 |
true | false | false |
aggressiveLazyLoading | 当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载(参考lazyLoadTriggerMethods ). |
true | false | false (true in ≤3.4.1) |
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 | 指定发现自动映射目标未知列(或者未知属性类型)的行为。NONE : 不做任何反应WARNING : 输出提醒日志 ('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior' 的日志等级必须设置为 WARN )FAILING : 映射失败 (抛出 SqlSessionException ) |
NONE, WARNING, FAILING | NONE |
defaultExecutorType | 配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新。 | SIMPLE REUSE BATCH | SIMPLE |
defaultStatementTimeout | 设置超时时间,它决定驱动等待数据库响应的秒数。 | 任意正整数 | Not Set (null) |
defaultFetchSize | 为驱动的结果集获取数量(fetchSize)设置一个提示值。此参数只可以在查询设置中被覆盖。 | 任意正整数 | Not Set (null) |
safeRowBoundsEnabled | 允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为false。 | true | false | False |
safeResultHandlerEnabled | 允许在嵌套语句中使用分页(ResultHandler)。如果允许使用则设置为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 常量. 大多都为: NULL, VARCHAR and OTHER | OTHER |
lazyLoadTriggerMethods | 指定哪个对象的方法触发一次延迟加载。 | 用逗号分隔的方法列表。 | equals,clone,hashCode,toString |
defaultScriptingLanguage | 指定动态 SQL 生成的默认语言。 | 一个类型别名或完全限定类名。 | org.apache.ibatis.scripting.xmltags.XMLLanguageDriver |
defaultEnumTypeHandler | 指定 Enum 使用的默认 TypeHandler 。 (从3.4.5开始) |
一个类型别名或完全限定类名。 | org.apache.ibatis.type.EnumTypeHandler |
callSettersOnNulls | 指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这对于有 Map.keySet() 依赖或 null 值初始化的时候是有用的。注意基本类型(int、boolean等)是不能设置成 null 的。 | true | false | false |
returnInstanceForEmptyRow | 当返回行的所有列都是空时,MyBatis默认返回null 。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集 (i.e. collectioin and association)。(从3.4.2开始) |
true | false | false |
logPrefix | 指定 MyBatis 增加到日志名称的前缀。 | 任何字符串 | 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 | 指定VFS的实现 | 自定义VFS的实现的类全限定名,以逗号分隔。 | Not set |
useActualParamName | 允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的工程必须采用Java 8编译,并且加上-parameters 选项。(从3.4.1开始) |
true | false | true |
configurationFactory | 指定一个提供Configuration 实例的类。 这个被返回的Configuration实例用来加载被反序列化对象的懒加载属性值。 这个类必须包含一个签名方法static Configuration getConfiguration() . (从 3.2.3 版本开始) |
No.5 注解
创建接口,使用 @Insert()、@Update()、@Select()、@Delete() 替代 xml 的语句
在配置文件中增加
一对多
@Results 通过 @Result 和 @Many 中调用多端方法相结合,来获取一对多关系
CategoryMapper
public interface CategoryMapper {
@Select("select * from category_")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "products",
javaType = List.class,
column = "id",
many = @Many(select = "com.kernel.pojo.ProductMapper.listByCategory"))
})
public List list();
}
ProductMapper
public interface ProductMapper {
@Select(" select * from product_ where cid = #{cid}")
public List listByCategory(int cid);
}
多对一
ProductMapper
@Select("select * from product_")
@Results(
@Result(property = "category", column = "id", one = @One(select = "com.kernel.pojo.CategoryMapper.get"))
)
public List list();
CategoryMapper
@Select("select * from category_ where id = #{id}")
public Category get(int id);
多对多
ProductMapper
public interface ProductMapper {
@Select("select * from product_ where id = #{id}")
public Product get(int id);
}
OrderItemMapper
public interface OrderItemMapper {
@Select("select * from order_item_ where oid = #{oid}")
@Results({
@Result(property = "product", column = "pid", one = @One(select = "com.kernel.pojo.ProductMapper.get"))
})
public List listByOrder(int oid);
}
OrderMapper
public interface OrderMapper {
@Select("select * from order_")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "orderItems", javaType = List.class, column = "id",
many = @Many(select = "com.kernel.pojo.OrderItemMapper.listByOrder"))
})
public List list();
}
动态 SQL
关于 sql 类
private String selectPersonSql() {
return new SQL() {{
SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FULL_NAME");
SELECT("P.LAST_NAME, P.CREATED_ON, P.UPDATED_ON");
FROM("PERSON P");
FROM("ACCOUNT A");
INNER_JOIN("DEPARTMENT D on D.ID = P.DEPARTMENT_ID");
INNER_JOIN("COMPANY C on D.COMPANY_ID = C.ID");
WHERE("P.ID = A.ID");
WHERE("P.FIRST_NAME like ?");
OR();
WHERE("P.LAST_NAME like ?");
GROUP_BY("P.ID");
HAVING("P.LAST_NAME like ?");
OR();
HAVING("P.FIRST_NAME like ?");
ORDER_BY("P.ID");
ORDER_BY("P.FULL_NAME");
}}.toString();
}
使用 SQL 类的方式构建
public class CategsoryDynaSqlProvider {
public String list() {
return new SQL()
.SELECT("*")
.FROM("category_")
.toString();
}
public String get() {
return new SQL()
.SELECT("*")
.FROM("category_")
.WHERE("id=#{id}")
.toString();
}
public String add(){
return new SQL()
.INSERT_INTO("category_")
.VALUES("name", "#{name}")
.toString();
}
public String update(){
return new SQL()
.UPDATE("category_")
.SET("name=#{name}")
.WHERE("id=#{id}")
.toString();
}
public String delete(){
return new SQL()
.DELETE_FROM("category_")
.WHERE("id=#{id}")
.toString();
}
}
注解
手写sql语句
@Insert(" insert into category_ ( name ) values (#{name}) ")
public int add(Category category);
使用sql类
@InsertProvider(type=CategoryDynaSqlProvider.class,method="add")
public int add(Category category);
No.6 延迟加载
MyBatis 默认是积极加载的,开启日志,一对多查询,走起
当我查询商品分类和商品时,控制台发送的sql如下:
DEBUG [main] - ==> Preparing: select * from category_
DEBUG [main] - ==> Parameters:
TRACE [main] - <== Columns: id, name
TRACE [main] - <== Row: 1, category1
TRACE [main] - <== Row: 2, category2
DEBUG [main] - <== Total: 2
category1
DEBUG [main] - ==> Preparing: select * from product_ where cid = ?
DEBUG [main] - ==> Parameters: 1(Integer)
TRACE [main] - <== Columns: id, name, price, cid
TRACE [main] - <== Row: 1, product a, 88.88, 1
TRACE [main] - <== Row: 2, product b, 88.88, 1
TRACE [main] - <== Row: 3, product c, 88.88, 1
DEBUG [main] - <== Total: 3
product a
product b
product c
category2
DEBUG [main] - ==> Preparing: select * from product_ where cid = ?
DEBUG [main] - ==> Parameters: 2(Integer)
TRACE [main] - <== Columns: id, name, price, cid
TRACE [main] - <== Row: 4, product x, 88.88, 2
TRACE [main] - <== Row: 5, product y, 88.88, 2
TRACE [main] - <== Row: 6, product z, 88.88, 2
DEBUG [main] - <== Total: 3
当我只查询商品分类时,发送的 sql 还是三条,所以 MyBatis 是默认开启积极加载的
开启延迟加载
再次查询,当我需要使用商品时,才发送对应的 sql
No.7 缓存
一级缓存
同一个 session 中查询相同的记录,只查询一次,不同 session,发送多次,所以一级缓存是 session 级别的。
二级缓存
二级缓存是 sessionFactory 的缓存
将映射文件中 sql 包含在 cache 标签中
insert into category_ ( name ) values (#{name})
delete from category_ where id= #{id}
update category_ set name=#{name} where id=#{id}
No.8 逆向工程
Mybatis Generator是一个用于Mybatis逆向工程的工具,通过表创建 pojo、mapper
导包 mysql-connector-java-5.0.8-bin.jar
generatorConfig.xml
测试
public class Test {
public static void main(String[] args) throws IOException, XMLParserException, InvalidConfigurationException, SQLException, InterruptedException {
List warnings = new ArrayList();
boolean overwrite = true;
InputStream is= Test.class.getClassLoader().getResource("generatorConfig.xml").openStream();
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(is);
is.close();
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
System.out.println("生成成功");
}
}
No.9 其他
日志
在 src 下创建 log4j.properties
# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.com.how2java=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
MyBatis 会自动打印出sql语句
分页
xml方式
注解方式
@Select("select * from category_ limit #{start},#{count}")
public List listByPage(@Param("start") int start, @Param("count") int count);
事务管理
将事务提交方式设置为 jdbc 后,将采用 jdbc 的方式提交事务,加入有一条记录失败,自动回滚,注意,数据表的类型必须是 INNODB
PageHelper
PageHelper 是一款 Mybatis 分页插件。
加入jar
pagehelper-5.1.0-beta2.jar、jsqlparser-1.0.jar
配置插件
分页查询只需要在执行查询之前,执行
PageHelper.offsetPage(0, 5);
获取总数
PageInfo page = new PageInfo<>(list);
网站题目:MyBatis基本入门篇
网页路径:http://myzitong.com/article/jdieos.html