MyBatis框架
一、引言
MyBatis优秀的持久层框架 ---- 将Java程序中处理的数据信息保存到数据库!
替换原始的JDBC开发方式,同时支持简单查询,存储过程,高级映射(表连接)和缓存。
JDBC中冗余的代码开发、SQL语句的固定书写(动态SQL)、手动ORM过于繁琐。
实现思想
二、开发步骤
1、搭建环境
jar包 核心 + 三方 + 数据库
配置文件
2.1 log4j.properties 位置:放到src根目录下即可
2.2 Mapper.xml 位置:随意 建议归包
书写<select … 等 SQL语句的配置文件 替换之前的 DAOImpl 实现类
2.3 mybatis-config.xml文件 位置:随意 但是建议src根目录
配置mybatis 核心参数 比如:连接中的conn等参数
初始化配置 ----> mybatis-config.xml
<configuration>
<!-- mybatis 数据库连接环境 s多个 default=“使用具体的某一个配置”-->
<environments default="oracle">
<environment id="oracle">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
<property name="username" value="hr"/>
<property name="password" value="hr"/>
</dataSource>
</environment>
</environments>
<!-- 注册mapper 替换DAOImpl 告诉mybaits你写了几个实现类 -->
<!-- com/baizhi/mapper/Mapper.xml 严格区分大小写 -->
<mappers>
<mapper resource="Mapper.xml的路径"/>
</mappers>
</configuration>
2、开发Mapper.xml
<!-- namespace="接口的全限定名称" -->
<mapper namespace="com.baizhi.dao.UserDAO">
<!-- id 方法名称 parameterType 参数类型 resultType 返回值类型 全限定名称 -->
<!-- #{id} 参数的获取 / sql 条件 = ? -->
<select id="queryUserByID" parameterType="int"
resultType="com.baizhi.entity.User">
select * from my_user where id = #{id}
</select>
</mapper>
3、初始环境的加载
//1.读取配置文件
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//2.获取sqlSessionFactory
SqlSessionFactory sqlSessionFactory =
new SqlSessionFactoryBuilder().build(is);
//3.获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//4.通过sqlSession对象获取DAO实现类
UserDAO userDAO = sqlSession.getMapper(UserDAO.class);
User user = userDAO.queryUserByID(1);
//5.关闭资源
sqlSession.close();
三、MyBatis参数绑定
如何传递数据以及如何接收数据!!!!
1、DAO方法中的参数(传递数据)
1.八种基本类型+String+Date
parameterType=“参数的类型” 可以省略
2.一个参数
<!-- 接口方法 : User queryUserByID(int id); -->
<select id="queryUserByID" resultType="com.baizhi.entity.User">
select * from my_user where id = #{id}
</select>
#{爱写啥写啥没人管} !!!!!
3.多个参数
1、方式一
<!-- 接口方法 : User queryUserByIDAndName(int id,String name); -->
<select id="queryUserByIDAndName" resultType="com.baizhi.entity.User">
select * from my_user where id = #{0} and name=#{1}
</select>
注意:0/1 代表了参数表的下标
2、方式二
使用注解 @Param("参数的名称")
<!-- User queryUserByIDAndName(@Param("id")int id,@Param("n")String name);-->
<select id="queryUserByIDAndName" resultType="com.baizhi.entity.User">
select * from my_user where id = #{id} and name=#{n}
</select>
4.用户自定义类型
方法 : User queryUserByNameAndPWD(User user);
<select id="queryUserByNameAndPWD" parameterType="com.baizhi.entity.User"
resultType="com.baizhi.entity.User">
select * from my_user where name = #{name} and password=#{password}
</select>
parameterType="用户自定义类型的全限定名称" 必须有!!!!
#{对象的属性名称}!!!!
参数是个集合!! 动态SQL再说!!!
5.数据的DML操作
MyBatis 默认数据回滚 需要开发者手动进行事务的提交!
sqlSession.commit();
void insertUser(User user);
<insert id="insertUser" parameterType="com.baizhi.entity.User">
insert into my_user values(#{id},#{name},#{password})
</insert>
//获取DAO接口的实现类对象
UserDAO userDAO = sqlSession.getMapper(UserDAO.class);
User user = new User(2,"gaojian","123456");
//提交事务
sqlSession.commit();
//关闭资源
sqlSession.close();
2、返回值类型
1.对象类型
resultType=“com.baizhi.entity.User” 返回对象的全限定名称
2.集合类型 List<User. / Set<.>
resultType=“com.baizhi.entity.User” 返回集合对象泛型的全限定名称 一模一样!!!!
注意:序列使用
方法一: 单表
<insert id="insertUser" parameterType="com.baizhi.entity.User">
insert into my_user values(my_seq.nextval,#{name},#{password})
</insert>
方法二: 多表操作会使用!!!
<insert id="insertUser" parameterType="com.baizhi.entity.User">
<!--keyProperty 查询出来的结果进行命名 在插入的时候使用 -->
<!--order="BEFORE" 执行顺序 resultType="int" 生成结果的Id 的类型 -->
<selectKey keyProperty="id" order="BEFORE" resultType="int">
select my_seq.nextval from dual
</selectKey>
insert into my_user values(#{id},#{name},#{password})
</insert>
四、Util的封装
- 冗余代码的抽取!!
- 效率 — 配置文件的读取一次 静态代码块!
- 线程绑定
private static SqlSessionFactory sqlSessionFactory = null;
static{
InputStream is = null;
try {
//在类加载的时候 只执行一次的配置文件读取!
is = Resources.getResourceAsStream("mybatis-config.xml");
//共享同一个工厂对象 重量级资源 类似 ServletContext
sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if(is!=null)try {is.close();} catch (IOException e) {}
}
}
private static ThreadLocal<SqlSession> tl = new ThreadLocal<SqlSession>();
//获取连接sqlsession
public static SqlSession getSqlSession() throws IOException{
SqlSession sqlSession = tl.get();
//没有连接对象 创建并绑定在当前线程中!!!
if(sqlSession==null){
sqlSession = sqlSessionFactory.openSession();
tl.set(sqlSession);
}
return sqlSession;
}
//资源的关闭 线程的解除绑定
public static void close(SqlSession sqlSession){
if(sqlSession!=null){
sqlSession.close();tl.remove();
}
}
//提交方法 并 关闭
public static void commit(SqlSession sqlSession){
if(sqlSession!=null){
sqlSession.commit();
close(sqlSession);
}
}
//回滚 并 关闭
public static void rollback(SqlSession sqlSession){
if(sqlSession!=null){
sqlSession.rollback();
close(sqlSession);
}
}
一、细节
1、实体类别名
<typeAliases>
<typeAlias type="com.baizhi.entity.User" alias="User"/>
</typeAliases>
简化parameterType=“User” resultType=“别名”
2、配置文件参数化
将大配置文件中可能存在修改的小范围数据提取到更为具体的小配置文件中,便于后期维护修改
<properties resource="jdbc.properties"></properties>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
二、ResultMap结果映射
resultType 、resultMap 出现在Mapper.xml中 都代表了返回的结果类型
当实体类和数据库字段不相同时,无法接收到数据?????
方式一、
select id,name username,password from my_user 直接在SQL语句中·使用as别名
方式二、
<!-- 标识 表中列名 和 实体类属性的对应关系 手动ORM-->
<!-- type="具体返回的实体类类型" id=“resultMap名称 随意”-->
<resultMap type="User" id="UserResultMap">
<id column="id" property="id"/> <!-- 主键列 -->
<result column="name" property="username"/> <!-- 其他非主键列 -->
<result column="password" property="password"/>
</resultMap>
<select id="queryAll" resultMap="UserResultMap" >
select * from my_user
</select>
三、jdbcType
MyBATIS 进行添加或修改操作时不允许进行空值数据操作。如果存在null的可能则需要进行jdbcType的使用
<insert id="insertUser" parameterType="User">
<selectKey keyProperty="id" order="BEFORE" resultType="int">
select my_seq.nextval from dual
</selectKey>
insert into my_user values(#{id},#{username},#{password,jdbcType=VARCHAR})
</insert>
#{列名,jdbcType=实际数据库列的类型}
四、多表操作
1、一对一关系
个人信息 和 身份证信息 两张表需要存在关联关系 — 外键
User : 用户表 ID、用户名、密码、手机、身份证号
id(主键)、username 、password、phone、idcard(外键)
IdentityCard : 身份证信息表 姓名、性别、民族、出生日期、住址、身份证号
realname、sex、nation、birthday、address、idcard(主键)
select * from User u
inner join IdentityCard i
on u.idCard = i.idCard
User表:
id(主键)、username 、password、 phone、 idcard
1 liuyangyang 123456 1111111111 12345678901234567
2 gaojianjian 654321 2222222222 12345678901234568
3 liuhanghang 123456 3333333333 12345678901234569
3 adada 111111 4444444444 1234567890123456x
IdentityCard表
realname、sex、nation、birthday、 address、idcard(主键)
刘洋 男 汉族 1980-01-01 北京昌平 12345678901234567
高健 男 xxx 1989-01-02 北京沙河 12345678901234568
。。。。。。
实体类怎么定义????
面向对象 对象的属性可以是另一个对象
MyBatis如何查询数据
2、一对多关系
一个部门多个员工 / 一个用户的多个地址 / 一个班级的多个学生…
Person员工 (表) : 字段 id name age sex
Deparmnent部门 (表) : 字段 dep_id depname description
注意:Struts + MyBatis 有一个jar包冲突,留一个就可以版本随意.
1.导入jar包 注意kar包的冲突
2.struts2的核心过滤器配置
3.引入配置文件
struts.xml / log4j.properties / mybatis-config.xml(初始化配置) / mapper.xml
4.代码~~~~
两张表 员工(id name password salary role(角色) 部门外键)和部门(dep_id depname)
1.登陆 需要在多一个password字段
2.展示所有员工信息以及其部门名称
3.删除判断 员工中添加 职称字段(员工 部门经理 总经理) 员工没有删除功能!
可选 部门经理删除员工 总经理都可以
- 可选 员工不能修改 (判断) 员工的角色要默认选中、选择新的部门(数据来源于数据库的查询)
3、多对多关系
学生 和 课程 商品和订单
Student表
stu_id 、 stu_name 、 hire_date
Course表
c_id 、 c_name 、 c_time
所有的学生以及每个学生所有的课程
public class Course {
private int c_id;
private String c_name;
}
public class Student {
private int stu_id;
private String stu_name;
private List<Course> courses;
}
<resultMap type="Student" id="StudentResultMap">
<id column="stu_id" property="stu_id"/>
<result column="stu_name" property="stu_name"/>
<collection property="courses" ofType="Course">
<id column="c_id" property="c_id"/>
<result column="c_name" property="c_name"/>
</collection>
</resultMap>
<select id="showAll" resultMap="StudentResultMap">
select s.*,c.* from t_student s
inner join t_stu_course sc
on s.stu_id = sc.stu_id
inner join T_course c
on c.c_id = sc.c_id
</select>
五、动态SQL
1. <sql id=""
代码片段,sql的复用。
<sql id="STU_COURSE_SQL">
s.stu_id,s.stu_name,c.c_id,c.c_name
</sql>
<select id="showAll" resultMap="StudentResultMap">
select <include refid="STU_COURSE_SQL"/>
from t_student s
inner join t_stu_course sc
on s.stu_id = sc.stu_id
inner join T_course c
on c.c_id = sc.c_id
</select>
2.where 条件
使用 where标签 以及 if 标签 动态判断用户传递的数据
如果数据不为null 则将数据拼接入where的查询条件
书写方式一、
<select id="queryProduct" parameterType="Product" resultType="Product">
select * from t_product
<where>
<if test="pro_id!=null">
pro_id = #{pro_id}
</if>
<if test="pro_name!=null">
and pro_name = #{pro_name}
</if>
<if test="pro_price!=null">
and pro_price = #{pro_price}
</if>
<if test="hire_date!=null">
and hire_date = #{hire_date}
</if>
</where>
</select>
书写方式二、
<trim prefix="WHERE" prefixOverrides="and|or"></trim>
两者全等于<where></where> 二选一
3. update 中的 set
update 表 set 列=值… where 条件
每一次修改不一定是一行数据的所有,有可能只是个别字段
方式一、
<update id="updateProduct" parameterType="Product">
update t_product
<set>
<if test="pro_name!=null">
pro_name=#{pro_name},
</if>
<if test="pro_price!=null">
pro_price=#{pro_price},
</if>
<if test="hire_date!=null">
hire_date=#{hire_date}
</if>
</set>
where pro_id=#{pro_id}
</update>
方式二、
<trim prefix="set" suffixOverrides=","></trim>
4. foreach遍历
void deleteProductS(List<Integer> ids)
SQL--->
delete from 表 where id in(?,?,?);
注意:
六、缓存
使用应该使用MyBATIS二级缓存、一级缓存是SqlSession默认的没什么用!!
1、配置
1.mybatis-config.xml
<!--声明 开启二级缓存 -->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
2.需要缓存的SQL语句的mapper.xml配置 只针对一个mapper.xml中的SQL查询
<cache></cache>
3.所有的实体类必须实现对象序列化接口
implements Serializable
2、注意
1. Cache Hit Ratio [com.baizhi.dao.ProductDAO]: 0.5 代表了缓存命中率
2. 当执行DML操作 会清空当前缓存
空间(金钱)换时间
七、连接池
import org.apache.ibatis.datasource.pooled.PooledDataSourceFactory;
import com.alibaba.druid.pool.DruidDataSource;
/**
* @author Administrator
* @time 上午11:12:44
* 2019年12月12日
*/
public class MyPOOLED extends PooledDataSourceFactory{
public MyPOOLED() {
this.dataSource = new DruidDataSource();
}
<dataSource type="com.baizhi.util.MyPOOLED">
<property name="driverClass" value="${driver}"/>
<property name="jdbcUrl" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
功能!
1.登陆 注册 强制登陆 验证码 安全退出
2.省份展示 修改 删除 添加
3.景点展示 修改 删除 添加
4.分页