Hibernate:全自动映射,虽然方便,但是缺少灵活性,后期还要深入学hql,麻烦。
MyBatis:半自动映射,sql语句写在配置文件中,由开发人员人员控制。
Mybatis也是轻量级框架
Mybatis实现sql语句定制化,其他流程还是自动化,是结余Hibernate和JDBC之间的半自动框架。
创建一个maven项目
pom文件的常用依赖
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.42</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
</dependencies>
小注意:
选成自己下载的maven
要打勾的地方
数据库
实体类(省略了get和set方法)
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
核心配置文件(必须要)
<?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">
<!-- mybatis的主配置文件 -->
```java
<configuration>
<!-- 配置properties-->
<properties resource="jdbcConfig.properties"></properties>
<!--配置参数-->
<settings>
<!--开启Mybatis支持延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"></setting>
</settings>
<typeAliases>
<!--typeAlias用于配置别名。type属性指定的是实体类全限定类名。alias属性指定别名,当指定了别名就再区分大小写
<typeAlias type="home.sise.cn.domain.User" alias="user"></typeAlias>-->
<!-- 用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不再区分大小写-->
<package name="home.sise.cn.domain"></package>
</typeAliases>
<!-- 配置环境 -->
<environments default="mysql">
<!-- 配置mysql的环境-->
<environment id="mysql">
<!-- 配置事务的类型-->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源(连接池) -->
<dataSource type="POOLED">
<!-- 配置连接数据库的4个基本信息 -->
<!-- <property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis_day01"/>
<property name="username" value="root"/>
<property name="password" value="3997"/>-->
<property name="driver" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</dataSource>
</environment>
</environments>
<!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件 -->
<!--<mapper resource="home/sise/cn/dao/IUserDao.xml"></mapper>-->
<!-- package标签是用于指定dao接口所在的包,当指定了之后就不需要在写mapper以及resource或者class了 -->
<package name="home.sise.cn.dao"></package>
</configuration>
连接池的属性有三个
POOLED 使用了连接池(常用)
UNPOOLED 没有使用连接池,每次请求都会创建一个链接
JNDI 需要通过服务器加载,必须是web工程或maven的war工程才能使用
mapper标签的属性
resource 用于配置xml方式
class 用于注解方式
package 直接指定dao接口包
typeAlias标签表示起别名
URI:Uniform Resource Identifier 统一资源标识符。它是在应用中可以唯一定位一个资源的。
URL:Uniform Resource Locator 统一资源定位符。它是可以唯一标识一个资源的位置。
URL用法:
http://localhost:8080/mybatis/ServletTest
协议 主机 端口 URI
在用户和账户的关联关系中,查询用户时,该用户的账户信息应该用的时候再查询。而查询账户时,该账户所属的用户信息应该一起查询出来。
延迟加载:不用的时候不查询。按需加载
立即加载:只要一调用方法,马上发起查询。
一对多,多对多:通常情况下我们都是采用延迟加载。
多对一,一对一:通常情况下我们都是采用立即加载。
配置properties
可以在标签内部配置连接数据库的信息。也可以通过属性引用外部配置文件信息
resource属性: 常用的
jdbcConfig.properties配置文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis_day01
jdbc.username=root
jdbc.password=3997
映射配置文件(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="home.sise.cn.dao.IUserDao">
<select id="findAll" resultType="home.sise.cn.domain.User">
select * from user
</select>
</mapper>
使用代理方式小注意:
1.mybatis的映射配置文件位置必须和dao接口的包结构相同
2.映射配置文件的mapper标签的namespace属性的取值要和dao接口的全限定类名相同
3.映射配置文件的select标签的id属性要和dao接口的方法名相同
原因
mybatis在创建工厂加载解析xml配置文件时,是通过把映射配置文件中的namespace+id作为key,把sq语句和返回类型作为value放入了map集合中。在我们使用时,通过传入的接口的全限定名+方法名从放入的map集合中找到对应的信息,然后执行相应的操作。
客户代码
public class Mybatis_test {
public static void main(String[] args)throws Exception {
//1.读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3.使用工厂生产SqlSession对象
// SqlSession session = factory.openSession();
SqlSession session = factory.openSession(true);
//4.使用SqlSession创建Dao接口的代理对象
IUserDao userDao = session.getMapper(IUserDao.class);
//5.使用代理对象执行方法
List<User> users = userDao.findAll();
for(User user : users){
System.out.println(user);
}
//提交事务
// session.commit();
//6.释放资源
session.close();
in.close();
}}
使用了建造者模式,工厂方法模式,代理模式
SqlSession session = factory.openSession(true);
表示开启了自动提交事务
接口实现类
public class UserDaoImpl implements IUserDao {
private SqlSessionFactory factory;
public UserDaoImpl(SqlSessionFactory factory){
this.factory = factory;
}
public List<User> findAll(){
//1.使用工厂创建SqlSession对象
SqlSession session = factory.openSession();
//2.使用session执行查询所有方法
List<User> users = session.selectList("home.sise.cn.dao.IUserDao.findAll");
session.close();
//3.返回查询结果
return users;
}
}
客户代码
public class MybatisTest {
public static void main(String[] args)throws Exception {
//1.读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3.使用工厂创建dao对象
IUserDao userDao = new UserDaoImpl(factory);
//4.使用代理对象执行方法
List<User> users = userDao.findAll();
for(User user : users){
System.out.println(user);
}
//5.释放资源
in.close();
}
}
常用增删改查
映射配置
```java
select last_insert_id();
insert into user(username,address,sex,birthday)values(#{userName},#{userAddress},#{userSex},#{userBirthday});
update user set username=#{userName},address=#{userAddress},sex=#{userAex},birthday=#{userBirthday} where id=#{userId}
delete from user where id = #{uid}
实体类
public class QueryVo {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
小注意:
1.parameterType为参数类型,resultType为返回值类型
2.因为在主配置文件中使用了别名,所以type中可以直接使用user,而且不区分大小写。
3.parameterType如果为8中基本类型,那么占位符#{}中的值可以任意,如果是其他值,则必须对应着实体类来写
4.当实体类和数据库的表没有一一对应时,可以使用在映射文件中给字段起别名或者resultMap
5.resultMap中,column是数据库字段,property是实体类属性,type是返回值类型,id是唯一标识。
if,where标签
<select id="findUserByCondition" resultMap="userMap" parameterType="user">
select * from user
<where>
<if test="userName != null">
and username = #{userName}
</if>
<if test="userSex != null">
and sex = #{userSex}
</if>
<if test="userAddress !=null">
and address = #{userAddress}
</if>
</where>
</select>
sql,foreach标签
foreach属性:
collection:代表要遍历的集合元素,类似jstl中的items
open:代表语句的开始部分
close:代表结束部分
item:代表遍历集合的每个元素,类似jstl中的var
sperator:代表分隔符
相当于sql: select * from user where ids != null and ids.size()>0 and id in (?)
<!-- 了解的内容:抽取重复的sql语句-->
<sql id="defaultUser">
select * from user
</sql>
<select id="findUserInIds" resultMap="userMap" parameterType="queryvo">
<include refid="defaultUser"></include>
<where>
<if test="ids != null and ids.size()>0">
<foreach collection="ids" open="and id in (" close=")" item="uid" separator=",">
#{uid}
</foreach>
</if>
</where>
</select>
小注意 resultMap中id标签是对应表中的主键 一个用户有多个账户 :一对多 缓存是什么? 为什么使用缓存? 适合用缓存的情况 不适合用缓存的情况 默认一级缓存,范围是在一个session中 二级缓存,范围是在一个sessionFactory中 第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
如果引用其它 mapper.xml 的 sql 片段,则在引用时需要加上 namespace,如下:
<!-- 定义User的resultMap-->
<resultMap id="userAccountMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!-- 配置user对象中accounts集合的映射 -->
<collection property="accounts" ofType="account" select="home.sise.cn.dao.IAccountDao.findAccountByUid" column="id"></collection>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="userAccountMap">
select * from user
</select>
<!-- 根据id查询用户 -->
<select id="findById" parameterType="INT" resultType="user">
select * from user where id = #{id}
</select>
方式二:
<!-- 定义User的resultMap-->
<resultMap id="userAccountMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!-- 配置user对象中accounts集合的映射 -->
<collection property="accounts" ofType="account">
<id column="id" property="id"></id>
<result column="uid" property="uid"></result>
<result column="money" property="money"></result>
</collection>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="userAccountMap">
select * from user u left outer join account a on u.id = a.uid
</select>
mybatis的缓存
存在内存中的临时数据。
减少和数据库的交互次数,提高了执行效率。
1.需要经常进行查询,而且不会经常变动的。
2.数据的正确与否对最终的结果影响不大。
1.经常改变的数据
2.数据的正确与否对最终的影响很大。
例如:商品的库存,银行的汇率.
当我们执行查询之后,查询的结果会同时存入到session为我们提供一块区域中。该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去session中查询是否有,有的话直接拿出来用。当session对象消失时,mybatis的一级缓存也就消失了。
当调用 session 的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存。
二级缓存存放的是数据
使用步骤:
第一步:让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
第三步:让当前的操作支持二级缓存(在select标签中配置)<mapper namespace="home.sise.cn.dao.IUserDao">
<!--开启user支持二级缓存-->
<cache/>
<!-- 根据id查询用户 -->
<select id="findById" parameterType="INT" resultType="user" useCache="true">
select * from user where id = #{uid}
</select>
</mapper>