功能篇1 日志、事务、延迟加载
准备:
此处只讨论Category和Proudct关系,因此数据库初始化只需要对这两个表进行初始化就行了。
drop database how2java;
create database how2java;
use how2java;
-- 分类表
CREATE TABLE category_ (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(32) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- 产品表
create table product_(
id int NOT NULL AUTO_INCREMENT,
name varchar(30) DEFAULT NULL,
price float DEFAULT 0,
cid int ,
PRIMARY KEY (id)
)AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- 插入数据
delete from category_;
INSERT INTO category_ VALUES (1,'衣服');
INSERT INTO category_ VALUES (2,'玩具');
delete from product_;
INSERT INTO product_ VALUES (1,'帽子', 30, 1);
INSERT INTO product_ VALUES (2,'鞋子', 20, 1);
INSERT INTO product_ VALUES (3,'袜子', 10, 1);
INSERT INTO product_ VALUES (4,'变形金刚', 50, 2);
INSERT INTO product_ VALUES (5,'赛车', 70, 2);
INSERT INTO product_ VALUES (6,'芭比娃娃', 100.5, 2);
通过注解的方式实现了Category与Product的1对多关系。
- CategoryMapper
// 根据id获取单个Category
@Select("select * from category_ where id= #{id} ")
public Category get(int id);
// 查询所有种类的id、name、包含的商品
@Select(" select * from category_")
@Results({ @Result(property = "id", column = "id"), @Result(property = "name", column = "name"),
// many属性表示一对多的关系,是另一个映射器里的查询结果
// 把Category的id传入到查询根据cid查询Product的方法里,获得一个列表
@Result(property = "products", javaType = List.class, column = "id", many = @Many(select = "com.huang.mapper.ProductMapper.listBycid")) })
public List<Category> list();
- ProductMapper
// 根据商品种类id查询,简单信息
@Select("select * from product_ where cid=#{cid}")
public List<Product> listBycid(int cid);
// 查询所有商品的基本信息、所属种类
@Select("select * from product_")
@Results({ @Result(property = "id", column = "id"), @Result(property = "name", column = "name"),
@Result(property = "category", column = "cid", one = @One(select = "com.huang.mapper.CategoryMapper.get")) })
public List<Product> list();
1 日志
1.1 导入日志包log4j
- 在lib文件夹下的 log4j.jar包build path。
- 在src目录下新建输出配置文件log4j.properties。用properties输出,输出等级为debug在控制台stdout输出。Eclipse默认的.properties配置文件的编码方式不合适,不能打中文,需要手动更改为UTF-8.
# 全局配置
log4j.rootLogger=debug, stdout
# 某个包下的输出级别
log4j.logger.com.huang=debug
# 输出格式配置
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n
- 更多输出配置项可以看以前的文章日志工具log4j
1.2 测试配置
Demo文件中查询id为1和2的Category
CategoryMapper mapper = session.getMapper(CategoryMapper.class);
System.out.println("查询第1个:");
Category c1=mapper.get(1);
System.out.println(c1);
System.out.println("查询第2个:");
Category c2=mapper.get(2);
System.out.println(c2);
1.3 日志有什么用
- MyBatis底层会自动输出日志信息,开启Debug信息可以看到与数据库的各种连接信息
-
2 事务
2.1 事务的特性
ACID特性
原子性(Atomicity) 原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
一致性(Consistency)
事务前后数据的完整性必须保持一致。
隔离性(Isolation)
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
事务的隔离级别。数据库
2.2 开启事务的功能
有问题的示范
- 先创建一个xml映射文件用来对数据库进行增删改操作。
<mapper namespace="com.huang.mapper.CategoryMapper">
<insert id="insertCategory" parameterType="Category" >
insert into category_ ( name ) values (#{name})
</insert>
<delete id="deleteCategory" parameterType="Category" >
delete from category_ where id= #{id}
</delete>
<update id="updateCategory" parameterType="Category" >
update category_ set name=#{name} where id=#{id}
</update>
</mapper>
- 在mybatis主配置文件中声明mapper。
<mapper resource="com/huang/mapper/CategoryMapper.xml" />
- 注意两个有关命名的点
- 主配置文件中的typealias标签,某个映射文件中映射项参数或返回结果是模型类,例如参数类型为com.huang.model.Category,在主配置文件中使用了这个标签,就只需要写Category。很方便。
<typeAliases>
<package name="com.huang.model" />
</typeAliases>
1. 映射文件中的namespace属性,一个项目里多个映射文件可能会有写映射项重复,重复的话就需要namespace+映射项名子来指定。namesapce通常就是当前所在的xml文件名。
<mapper namespace="com.huang.mapper.CategoryMapper">
- 写一个Demo测试,一个事务中两个插入操作,第一个插入操作正常,第二个插入操作名字很长,肯定会失败。
System.out.println("新增加id为3");
session.insert("insertCategory","id为3的category");
System.out.println("新增加id为4:");
session.insert("insertCategory","id为4的category,hahahahhahhahahhahahahahhahahhahahahhahahhahahah");
- 正确的操作
- 发现上述没有效果,没有体现事务的原子性。
- 原因是这个Category表的引擎不对,应该使用InnoDB。
show table status from how2java;
- 重新初始化数据库信息,并且使用InnoDB引擎后可以看到原子性。
alter table category_ ENGINE = innodb;
3 延迟加载
3.1 什么是延迟加载
- 基于前面注解的Category与Product一对多的方式进行查询。只输出Category的名字。
CategoryMapper mapper=session.getMapper(CategoryMapper.class);
List<Category> cs = mapper.list();
for (Category c : cs) {
System.out.println(c.getName());
// List<Product> ps = c.getProducts();
// for (Product p : ps) {
// System.out.println("\t"+p.getName());
// }
}
- 修改日志配置输出界别trace,显示更加具体的信息。
log4j.logger.com.huang=trace
- 发现即使没有输出相关的Product信息,也会进行Product查询。
延迟加载希望不输出相关Product信息就不要查询了减少对数据库的操作。
3.2 开启延迟加载
修改MyBatis主配置。必须在configuration标签下第一个配置这个标记。
<settings>
<!-- 打开延迟加载的开关 -->
<setting name="lazyLoadingEnabled" value="true" />
<!-- 将积极加载改为消息加载即按需加载 -->
<setting name="aggressiveLazyLoading" value="false" />
</settings>