功能篇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.ConsoleAppenderlog4j.appender.stdout.layout=org.apache.log4j.PatternLayoutlog4j.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>

