1.JDBC的操作步骤。
2.mybatis的框架原理图:
基础支撑层:就是数据库的相应的配置。
1.操作步骤。
第一步加载相应的jar包。
第二步:编写输出日志文件:log4j.properties(可选项)
# Configure logging for testing: optionally with log file
log4j.rootLogger=DEBUG, stdout
# log4j.rootLogger=WARN, stdout, logfile,\u5982\u679C\u662F\u751F\u4EA7\u73AF\u5883\u5C31\u662FINFO,ERROR
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
第三步:编写jdbc的配置文件(针对数据库的一些配置。)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 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/shop" />
<property name="username" value="root" />
<property name="password" value="123" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml" />
</mappers>
</configuration>
第四步:编写PreparedStatement处理的sql文本。这个文本是写在配置文件里,比如我针对cate这张表的操作,那么会创建一个catemapper.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="test">
<!-- id是必须写的。
parameterType:参数的类型
resultType是结果映射的对象 -->
<select id="selectCateOne" parameterType="java.lang.Integer" resultType="com.gxa.bj.model.Cate">
Select * From cate Where id=#{id}
</select>
</mapper>
第五步:需要将该sql配置文件加入到基础配置文件里(mybatis-config.xml文件里)
第六步,Mybatis的操作程序。
操作示范代码:
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory =new SqlSessionFactoryBuilder().build(inputStream);
//产生一个SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
Cate cate = sqlSession.selectOne("test.selectCateOne", 2048);//找相应的sql语句就需要通过命名空间的方式去操作
System.out.println("分类名称:"+cate.getName());
sqlSession.close();
不同的sql语句的sql配置文件的编写
1.查询的时候做模糊查询。
<select id="selectMany" parameterType="java.lang.String" resultType="com.gxa.bj.model.Cate">
Select * From cate Where name like '%${value}%'
</select>
2.普通的插入语句:
<insert id="insertCate" parameterType="com.gxa.bj.model.Cate">
Insert into Cate(name,description) values(#{name},#{description})
</insert>
3.插入语句之后,获取刚插入的主键的数据:
<insert id="insertCate" parameterType="com.gxa.bj.model.Cate">
<selectKey keyProperty="id" resultType="java.lang.Integer" order="AFTER">
select last_insert_id()
</selectKey>
Insert into Cate(name,description) values(#{name},#{description})
</insert>
如果是mysql的uuid。那么sql的编写为:
<insert id="insertCate" parameterType="com.gxa.bj.model.Cate">
<selectKey keyProperty="id" resultType="java.lang.Integer" order=“BEFORE">
select uuid()
</selectKey>
insert into cate(id,name,description)values(#{id},#{name},#{description})
</insert>
如果是oracle的序列,那么sql的编写为:
<insert id="insertCate" parameterType="com.gxa.bj.model.Cate">
<selectKey keyProperty="id" resultType="java.lang.Integer" order=“BEFORE">
select 序列名.nextval()
</selectKey>
insert into cate(id,name,description)values(#{id},#{name},#{description})
</insert>
更新的sql语句:
<update id="updateCate" parameterType="com.gxa.bj.model.Cate">
update cate set name=#{name},description=#{description} where id=#{id}
</update>
删除语句:
<delete id="deleteCate" parameterType="java.lang.Integer">
delete from cate from id=#{id}
</delete>
第二天 Mybatis 开发dao层
1.开发的时候,一般会将jdbc连接的属性写入到jdbc.properties文件中。配置信息如下:
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/shop
jdbc.username=root
jdbc.password=123
2.将该配置文件的内容导入到SqlMapConfig.xml(Mybatis的基础信息配置)中。
<?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>
<properties resource="jdbc.properties"><!—把jdbc的配置信息写入到该文件中à
</properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/gxa/bj/model/CateMapper.xml" />
</mappers>
</configuration>
3.通过Mapper映射的方式去实现sql操作。
1)在dao层首先是定义了一个接口,比如这里的接口名字CateMapper:
public interface CateMapper {
public List<Cate> selectAllCate();
}
2)在dao层配置CateMapper.xml文件。
3)操作的时候,实际是通过生成动态代理对象。
CateMapper cateMapper = sqlSession.getMapper(CateMapper.class);//实际就是生成了动态代理的对象
List<Cate> listCate = cateMapper.selectAllCate();
3.动态SQL语句的操作,是根据传入的参数不一样,所生成的sql语句也不相同。在生成的时候,一定要写清楚它的判定规则:比如:
<select id="selectCateByParam" resultType="com.gxa.bj.model.Cate"
parameterType="com.gxa.bj.model.Cate">
Select * From cate where 1=1
<if test="id>0">
And id=#{id}
</if>
<if test="name!=null">
And name like '%${name}%'
</if>
<if test="description!=null">
And description like '%${description}%'
</if>
</select>
4.在Mybatis中操作表与表之间的关联的操作
第一种实现方式:
1)操作1:多对一的关系的操作,比如产品表与产品分类表。那么需要在产品表的数据里加入产品分类表的数据。产品表的实体类:Product,分类表的实体类:Cate
a.新建一个对象,这个对象是包含产品表的数据和产品分类的数据。这个对象的名字是ProductItem,它是继承自Product。
public class ProductItem extends Product {
public String getCateName() {
return cateName;
}
public void setCateName(String cateName) {
this.cateName = cateName;
}
public String getCateDescription() {
return cateDescription;
}
public void setCateDescription(String cateDescription) {
this.cateDescription = cateDescription;
}
private String cateName;
private String cateDescription;
}
b.创建相应的Mapper接口,比如叫ProductMapper接口。定义方式如下:
public interface ProductMapper {
public ProductItem getModel(int id);
}
C.创建ProductMapper.xml配置文件,配置文件格式如下:
<mapper namespace="com.gxa.bj.dao.ProductMapper">
<select id="getModel" resultType="com.gxa.bj.model.ProductItem">
Select p.*,c.name as cateName,
c.description as cateDescription
From Cate as c,Product p
Where c.id = p.cate_id
and p.id = #{id}
</select>
</mapper>
第二种实现方式:
多对一的关系的实现:在多的实体对象里包含一的实体对象
要求一个实体对象里必须包含另外的一个实体对象。比如说Product里必须包含的是Cate对象。
1)首先应该配置结果集(数据结果应该如何显示的)。配置的方式如下:
<!-- 配置结果集(查询的数据最终映射的对象的字段的关联)
type:表示同哪个实体对象进行映射的
id:表示这个结果的名字,后面如果要用到该结果集就会引用该名字
-->
<resultMap type="com.gxa.bj.model.Product" id="productInfoResult">
<!-- 表示主键字段 -->
<id property="id" column="id" />
<!-- result就是形成一个映射关系,查询出的数据的字段映射成实体对象里的字段
property:表示的是实体对象的字段名字
column:表示的是查询出的数据的列名
-->
<result property="iprice" column="iprice"></result>
<result property="isHot" column="isHot"></result>
<result property="isShow" column="isShow"></result>
<result property="mprice" column="mprice"></result>
<result property="name" column="name"></result>
<result property="num" column="num"></result>
<result property="pubTime" column="pubTime"></result>
<result property="sn" column="sn"></result>
<result property="cate_id" column="cate_id"></result>
<!-- 关联另外一个实体对象 -->
<association property="cate" javaType="com.gxa.bj.model.Cate">
<!--为了保证列名不起冲,对应的列名起另外一个名字 -->
<id property="id" column="cateid"></id>
<result property="description" column="description"></result>
<!--为了保证列名不起冲,对应的列名起另外一个名字 -->
<result property="name" column="catename"></result>
</association>
</resultMap>
2)在接口中定义方法:
public interface ProductMapper {
public ProductItem getModel(int id);
public Product getProductModel(int id);
}
3)在ProductMapper.xml文件中实现的配置:
<!-- id名字对应到的接口的方法名,
resultMap:返回的结果映射应该对应到我们自己配置的映射集的名字。
-->
<select id="getProductModel" resultMap="productInfoResult">
Select p.*,c.id as cateid,c.name as catename,
c.description
From Cate as c,Product p
Where c.id = p.cate_id
and p.id = #{id}
</select>
一对多的关系映射。比如产品分类表对应多个产品明细表。
1)需要在产品分类表里加入产品明细表的集合对象的数据:
public class Cate {
private Integer id;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
private String name;
private String description;
//形成一对多的关系映射
private List<Product> productList;
public List<Product> getProductList() {
return productList;
}
public void setProductList(List<Product> productList) {
this.productList = productList;
}
}
2)配置结果集:
<resultMap type="com.gxa.bj.model.Cate" id="cateMapResult">
<id column="cateid" property="id"></id>
<result property="description" column="description"></result>
<result property="name" column="name"></result>
<!-- ofType:表示的是集合里的pojo的类型:
resultType:表示对应的pojo的映射数据
-->
<collection property="productList" ofType="com.gxa.bj.model.Product"
resultMap="com.gxa.bj.dao.ProductMapper.productInfoResult">
</collection>
</resultMap>
3)编写相应的sql语句的配置:(注意对于列名相同的情况,比如id相同的处理,加入不同的列名进行区分)
<select id="selectAllCate" resultMap="cateMapResult">
Select c.id as cateid ,c.name,c.description,p.*
From cate c,product p
Where c.id=p.cate_id
</select>
带查询条件的Mybatis分页的实现。
1)实现原理,在定义参数的时候,需要告诉Mybatis。这是一个参数。所以在定义接口中的方法的时候,它的参数的设定方式:
public List<Cate> selectCateByPage(@Param("startNum") int startNum,@Param("pageSize") int pageSize,@Param("c")Cate c);
2)在SQL语句的实现的时候:需要对这些参数做设置。
<!-- 带有分页查询条件的SQL语句 -->
<select id="selectCateByPage" parameterType="com.gxa.bj.model.Cate"
resultType="com.gxa.bj.model.Cate">
Select * From cate
where 1=1
<if test="c.id>0">
And id=#{c.id}
</if>
<if test="c.name!=null">
And name like '%${c.name}%'
</if>
<if test="c.description!=null">
And description like '%${c.description}%'
</if>
limit #{startNum},#{pageSize}
</select>
Mybatis的延迟加载:
1)延迟加载:
先从单表查询、需要时再从关联表去关联查询,大大提高 数据库性能,因为查询单表要比关联查询多张表速度要快。
resultMap可以实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具备延迟加载功能。 延迟加载的属性:fetchType="lazy"
2)缓存及设置。
二级缓存是针对namespace下的缓存,开启mapper下的二级缓存:
<cache/>useCache配置 在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。
<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false"> 。
总结:针对每次查询都需要最新的数据sql,要设置成useCache=false,禁用二级缓存。
1.一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。
2. 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。
3. 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。
第三天 Spring同Mybatis集成
1.需要Spring给Mybatis提供什么容器?
1)提供SqlSessionFactory的注入。
2)提供产生SqlSession的注入。
2.开发步骤:首先引入jar包:
2)创建一个applicationContext.xml的配置文件,在配置文件里声明一个dataSource。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- 配置数据源的bean -->
<bean id="dataSource" destroy-method="close" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/shop"/>
<property name="user" value="root"/>
<property name="password" value="123"/>
<property name="maxPoolSize" value="40"/>
<property name="minPoolSize" value="1"/>
<property name="initialPoolSize" value="1"/>
<property name="maxIdleTime" value="60"/>
<property name="checkoutTimeout" value="2000"/>
</bean>
</beans>
3.在声明一个SqlSessionFactoryBean的对象,声明该对象的时候需要注意的就是通过Spring同Mybatis的jar包提供的。
<!-- 声明一个SqlSessionFactoryBean的对象 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
</bean>
4.开发model层和dao层。
5.配置mybatis-config.xml的配置文件
6.在applicationContext中加入mybatis-config.xml的配置文件,重写修改之前的bean文件:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
</bean>
完成以上步骤之后的开发目录的结构:
接下来程序的代码实现:
1)比如需要实现CateDao的接口。那么需要创建一个类CateDaoImp:
public class CateDaoImp extends SqlSessionDaoSupport implements CateMapper {
@Override
public List<Cate> selectAllCate() {
// TODO Auto-generated method stub
return null;
}
@Override
public List<Cate> selectCateByParam(Cate c) {
// TODO Auto-generated method stub
return null;
}
@Override
public List<Cate> selectCateByPage(int startNum, int pageSize, Cate c) {
// TODO Auto-generated method stub
return null;
}
}
2)在spring中配置访问该dao对象的bean。
<!-- 访问dao层的bean对象 -->
<bean id="cateDaoImp" class="com.gxa.bj.dao.imp.CateDaoImp">
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
3)具体的实现方法:
@Override
public List<Cate> selectAllCate() {
// TODO Auto-generated method stub
SqlSession session = this.getSqlSession();
CateMapper c = session.getMapper(CateMapper.class);
return c.selectAllCate();
}
另外注意(重点):扫描的时候只能扫描接口。
包的扫描,扫描一个包下面的所有的java对象,然后给所有的java对象注入属性值。
- 通过MapperScannerConfigurer进行mapper扫描
配置 :
<!-- 通过包的扫描将包下面的所有类扫描到bean中,所有的bean名字为首字母小写 ,
命名:如果扫描到CateDaoImp这个类,那么bean的名字为cateDaoImp
如果是多个包就加逗号分隔开
-->
<!--扫描的时候只能扫描到接口。所以这里就只能扫描到com.gxa.bj.dao这个接口
通过包的扫描将包下面的所有接口扫描到bean中,所有的bean名字为首字母小写 ,
命名:如果扫描到CateMapper这个接口,那么bean的名字为cateMapper
如果是多个包就加逗号分隔开
-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.gxa.bj.dao"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
测试代码:
ApplicationContext appContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
CateMapper cateDaoImp =(CateMapper) appContext.getBean("cateMapper");
List<Cate> list= cateDaoImp.selectAllCate();
for(Cate c : list){
System.out.println("FENLEI:"+c.getName());
}