Mybatis环境搭建,CRUD,动态sql,缓存,延时加载

什么是框架?

他是我们软件开发中的一套解决方案,不同的框架解决不同的问题
使用框架的好处:
框架封装了很多的细节,使开发者可以使用极简的方法实现功能,大大提高开发效率

什么是三层架构?

表现层: 用于展示数据
业务层: 是处理业务需求
持久层: 和数据库进行交互

持久层技术解决方案
         JDBC技术:
                        Connection
                        PreparedStatement
                        ResultSet
          SpringJdbcTemplate:
                        Spring中对JDBC的简单封装
          Apache的DBUtils
                        和Spring的JDBCTemplate很像,都是简单封装

  以上都不是框架
      JDBC是规范
      Spring的JdbcTemplate和Apache的DBUtils都只是工具类

Mybatis框架概述:

是一个优秀的基于java的持久层框架,它内部封装了jdbc很多细节,所以我们只需关注sql语句本身,无需关注加载驱动,获取连接,创建statement对象等过程,使用ORM思想实现结果集的封装.

ORM(Object Relational Mapping) :对象关系映射

就是把数据库表和实体类的属性对应起来,让我们可以操作实体类就实现操作数据库表

mybatis的环境搭建:

1.创建maven工程并导入坐标
2.创建实体类和dao的接口
3.创建Mybatis的主配置文件
SqlMapConfig.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">

<!--mybatis的主配置文件-->
<configuration>
    <!--配置环境-->
    <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/test"/>
                <property name="user" value="debian-sys-maint"/>
                <property name="password" value="YN6bICN3ccV5FbIn"/>
            </dataSource>
        </environment>
    </environments>

    <!--指定映射配置文件的配置,映射配置文件是指给每个Dao独立的配置文件-->
    <mappers>
        <mapper resource="com/tulun/dao/IUserDao.xml"></mapper>
    </mappers>
</configuration>

4.创建映射配置文件
IUserDao.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="com.tulun.dao.IUserDao">
    <!--配置查询所有-->
    <select id="findAll">
        select *from user
    </select>
</mapper>

环境搭建的注意事项:
1.创建IUSerDao.xml 和 IUserDao.java时名称是为了和我们之前的知识保持一致,在Mybatis中,他把持久层的操作接口名称和映射文件也叫作:Mapper
所以IUserDao 和IUserMapper是一样的
2.在idea创建目录的时候,他和包是不一样的, 包在创建时:com.tulun.dao他是三级目录 目录在创建时:com.tulun.dao他是一级目录
3.mybatis的映射配置文件位置必须和dao接口的包结构相同
4.映射配置文件的mapper标签的namespace属性的取值必须是dao接口的全限定类名
5.映射配置文件的操作配置(select ),id属性必须是dao接口的方法名 当我们遵从了3,4,5点之后,我们在开发中就无需在写dao的实现类

Mybatis的基本代码:

第一步:读取配置文件
第二步:创建SqlSessionFactory工厂
第三步:创建SqlSession对象
第四步:创建Dao接口的代理对象
第五步:执行dao中的方法
第六步:释放资源

		//加载SqlMapConfig.xml配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory会话工厂
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
        //创建会话
        SqlSession sqlSession = sessionFactory.openSession();
        //获取代理对象
        AccountDao accountDao = sqlSession.getMapper(AccountDao.class);
		//查询
        List<Account> accounts = accountDao.findAll();

        for(Account account : accounts) {
            System.out.println(account);
        }

        in.close();
        sqlSession.close();

Mybatis的CRUD操作

<mapper namespace="com.tulun.dao.IUserDao">

    <!--配置查询所有的结果的列名和实体类属性名的对应关系-->
    <resultMap id="userMap" type="com.tulun.domain.User">
        <!--配置主键字段的对应-->
        <!-- <id property="" column=""></id> -->
        <!--非主键字段的对应-->
        <!-- <result property="userId" column="id"></result> -->
        <result property="userName" column="username"></result>
        <result property="userSex" column="sex"></result>
        <result property="UserBirthday" column="birthday"></result>
        <result property="userAddress" column="address"></result>
    </resultMap>

    <!--查询所有-->
    <select id="findAll" resultMap="userMap">
        select *from user;
    </select>
    
    <!--保存用户  parameterType:参数的类型-->
    <insert id="saveUser" parameterType="com.tulun.domain.User">
        <!--配置插入操作后,获取插入数据的id-->
        <selectKey keyProperty="userId" keyColumn="id" resultType="Integer" order="AFTER">
            select last_insert_id();
        </selectKey>
        insert into user(id,username,birthday,sex,address)values (#{userId},#{userName},#{UserBirthday},#{UserSex},#{UserAddress});
    </insert>
    
    <!--更新用户-->
    <update id="updateUser" parameterType="com.tulun.domain.User">
        update user set username=#{userName},birthday=#{UserBirthday},address=#{UserAddress} where id=#{id};
    </update>

    <!--删除用户-->
    <delete id="deleteUser" parameterType="Integer">
        delete from user where id=#{id};
    </delete>

    <!--根据id查询用户-->
    <select id="findById" parameterType="Integer" resultMap="userMap">
        select * from user where id=#{id};
    </select>
    
    <!--根据用户名查询 模糊查询-->
    <select id="findByName" parameterType="java.lang.String" resultMap="userMap">
        <!--select * from user where username like #{username}; -->
        select * from user where username like '%${value}%'
    </select>

    <!--查询总用户数-->
    <select id="findTotal" resultMap="userMap">
        select count(id) from user;
    </select>

    <!--根据queryVo的条件查询用户-->
    <select id="findUserByVo" parameterType="com.tulun.domain.QueryVo" resultMap="userMap">
        select * from user where username like #{user.userName};
    </select>
</mapper>

Mybatis的参数深入:
parameterType(输入类型):传递简单类型
传递pojo(实体类)对象
传递pojo包装对象 什么是ognl表达式:Object(对象) Graphic(图) Navigation(导航) Language(语言)
它是通过对象的取值方法来获取数据.在写法上吧get省略了.比如:获取用户的名称:
类中的写法:user.getUsername();
ognl表达式写法:user.username; mybatis中为什么可以直接写username而不用user.呢
因为在parameterType中已经提供了属性所属的类,所以比用些对象名.

Mybatis的标签使用:

properties标签:

<!--配置properties
    可以在标签内部配置连接数据库的信息.也可以通过属性引用外部配置文件信息
    resource属性:
        用于指定配置文件的位置,是按照类路径的写法来写,必须存在类路径下.
    url属性:
        是要求按照Url的写法来写地址
        URL: Uniform Resource Locator 统一资源定位符.他是可以唯一标识一个资源的位置
        它的写法:
            http://localhost:8080/mybatisserver/demoSerlet
            协议  主机   端口     URI
        URI:Uniform Resource Identifier 统一资源标识符.他是在应用中可以唯一定位一个资源的
-->

<!--配置properties 1.通过加载配置文件的方式 配置resource属性-->
<properties resource="jdbcConfig.properties"></properties> 

<!--配置properties 2.通过配置url的方式-->
<properties url="file:///home/fly/IdeaProjects/mybatis/mybatis_CRUD/src/main/resources/jdbcConfig.properties"></properties>

typeAliases标签:


<!--使用typeAliases 配置别名.只能配置domain中的类的别名-->
<typeAliases>
一. <!--typeAlias用于配置别名 type属性指定的是实体类全限定类名 ,alias属性指定别名,当指定了别名之后就不在区分大小写-->
    <typeAlias type="com.tulun.domain.User" alias="user"></typeAlias>

二. <!--用于指定配置别名的包 ,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不区分大小写-->
    <package name="com.tulun.domain"/>
</typeAliases>

<!--配置映射文件-->
<mappers>
    <mapper resource="com/tulun/dao/IUserDao.xml"></mapper>

    <!--package标签是指定dao接口所在的包,当指定之后就不需要再写mapper 以及resource 或者class-->
    <package name="com.tulun.dao"/>\
</mappers>

mapper里的标签(可以实现动态sql)

if标签

<!--根据条件查询-->
<select id="findUserByCondition" parameterType="user" resultMap="userMap">
    select *from user where 1=1
    <if test="userName != null ">
        and username =#{userName}
    </if>
</select>

where标签

<select id="findUserByCondition" parameterType="user" resultMap="userMap">
    select *from user
    <where>
        <if test="userName != null ">
            and username =#{userName}
        </if>
        <if test="UserSex !=null">
            and sex =#{UserSex}
        </if>
    </where>
</select>

sql标签

<!--了解的内容 用于抽取重复的语句-->
<sql id="defaultUser">
    select *from user;
</sql>

<!--查询所有-->
<select id="findAll" resultMap="userMap">
    <include refid="defaultUser"></include>
</select>

foreach标签

<!--根据queryVo的id集合 实现查询用户列表-->
<select id="findUserInIds" resultMap="userMap" parameterType="queryVo">
    select * from user
    <where>
        <if test="ids != null and ids.size()>0">
            <foreach collection="ids" open="and id in(" close=")" item="id" separator=",">
            <!--这个id 由 item的 id 决定-->
                #{id}
            </foreach>
        </if>
    </where>
</select>

连接池:

可以减少我们获取连接所消耗的时间. (连接池就是一个用于存储连接的容器,容器就是一个集合对象,该集合必须是线程安全的,不能两个线程拿到同一个连接,该集合还必须实现队列的特性:先进先出) ```


mybatis中的连接池:
    mybatis连接池提供了三种方式的配置
    配置的位置:
       主配置文件SqlMapConfig.xml中的datasource标签,type属性表示采用那种连接池的方式
       type的取值:
           POOLED :采用传统的javax.sql.DataSource规范中的连接池 ,mybatis中有针对规范的实现(相当于我们手动创造一个连接)
           UNPOOLED :采用传统的获取连接的方式,虽然也实现了javax.sql.DataSource接口,但是并没有采用池的思想.
          (拓展)   JNDI :采用服务器提供的JNDI技术实现来获取DataSource对象,不同的 服务器拿到的dataSource是不一样的.
          注意:如果不是web或者maven的war工程,是不能使用的.
    我们测试时候使用tomcat服务器,采用的连接池:dbcp连接池

Mybatis的延迟加载

问题:在一对多中,有一个用户,他有100个账户,在查询的时候,要不要吧关联的账户查出来?
在查询用户时,用户下的账户信息应该是什么时候使用,什么时候查询
在查询账户时,账户的所属用户信息应随着账户查询时一起查出来
什么是延迟加载
在真正使用数据时才发起查询,不用的时候不查询(按需加载,懒加载)
什么是立即加载
不管用不用,只要调用方法,马上发起查询
在对应的四种表关系中:一对一 多对一 一对多 多对多
一对多,多对多:通常情况下采用延迟加载.
多对一,一对一:通常情况下采用立即加载.

//SqlMapConfig文件:

<!-配置参数--->
<settings>
          <!--开启Mybatis支持延迟加载-->    
          <setting name ="lazyLoadingEnable" value = "true"/>  //默认值为true

          <!--当开启时,任何方法的调用都会加载该对象的所有属性-->
          <setting name ="aggressiveLazyLoading" value = "false"/></setting> 
</settings>

mybatis中的一级缓存和二级缓存

一级缓存:

mybatis的sqlSession对象的缓存

但我们执行查询之后,查询的结果会同时存入到sqlSession为我们提供的区域,该区域的结构是一个map.
当我们再一次查询同样的数据,mybatis会先去sqlSession中查看是否有,有的话直接拿出来用,
当sqlSession对象消失后,mybatis的一级缓存也就消失了. 
sqlSession.clearCache();可以清空缓存 
当调用sqlSession的修改,添加,删除,commit()等方法时,就会清空一级缓存

     User user1 = userDao.findById(1);
     System.out.println(user1);
     sqlSession.clearCache();  //清空缓存
     //update(),commit(),delete();
     User user2 = sqlSession.getMapper(IUserDao.class).findById(1);
     System.out.println(user2);
     System.out.println(user1 == user2);
     
打印结果:
com.tulun.domain.User@6c64cb25
com.tulun.domain.User@5158b42f
false

二级缓存

指的是mybatis中的sqlSessionFactory对象的缓存,由同一个sqlSessionFactory对象创建的sqlSession共享其缓存. 二级缓存存放的是数据,不是对象

二级缓存的使用步骤: 
1.让mybatis框架支持二级缓存(在sqlMapConfig.xml中配置)

<!--配置二级缓存-->
<setting name="cacheEnabled" value="true"/>

2.让当前的映射文件支持二级缓存(在IUserDao.xml中配置)

<!--开启user支持二级缓存-->
<cache/>

3.让当前的操作支持二级缓存(在select标签中配置)

<select id="findById" resultType="com.tulun.domain.User" useCache="true">
        select *from user where id =#{id}
</select>

Mybatis的注解开发:

注解代码:
SqlMapConfig.xml

<mappers>
        <package name="com.tulun.dao"/>
</mappers>

IUserDao ( Interface )

/**
 * 查询所有
 * @return
 */
@Select("select *from user")
List<User> findAll();

/**
 * 保存用户
 * @param user
 */
@Insert("insert into user(id,username,address,sex,birthday) value(#{id},#{username},#{address},#{sex},#{birthday})")
void saveUser(User user);

/**
 * 更新用户
 * @param user
 */
@Update("update user set username=#{username},sex=#{sex},birthday=#{birthday},address=#{address} where id =#{id}")
void updateUser(User user);

/**
 * 删除用户
 * @param id
 */
@Delete("delete from user where id =#{id}")
void deleteUser(Integer id);

/**
 * 查询一个用户
 * @param id
 * @return
 */
@Select("select * from user where id=#{id}")
User findUserById(Integer id);

/**
 * 根据名字查询用户
 * @param name
 * @return
 */
@Select("select * from user where username like #{username}")
List<User> findUserByName(String name);

注意:使用注解开发的时候,就不必配置com.tulun.dao.IUserDao.xml文件,因为如果两个都有,mybatis加载的时候,就不知道该怎么办.

IUserDao(Interface)

举例://如果User实体类属性名和数据库属性名不一样,可以使用以下标签
@Results(id = "userMap",value = {
        @Result(id = true, column = "id",property = "userId"),//id为主键
        @Result(column = "username",property = "userName"),
        @Result(column = "sex",property = "userSex"),
        @Result(column = "birthday",property = "userBirthday"),
        @Result(column = "address",property = "userAddress"),
})
/**
 * 查询所有
 * @return
 */
@Select("select *from user")
@ResultMap(value = {"userMap"})   //标准写法
List<User> findAll();

多表查询操作

多对一(账户查用户)

在mybatis中,多对一的查询就是一对一(多个账户对应一个用户 mybatis认为:一个账户对应一个用户)
在Account实体类中就应该有一个private User user; 属性
IAccountDao(Interface)
@Results(id = "accountMap",value = {
        @Result(id = true, column = "id",property = "userId"),//id为主键
        @Result(column = "uid",property = "uid"),
        @Result(column = "money",property = "money"),
        @Result(property = "user",column = "uid",one = @One(select = "com.tulun.dao.IUserDao.findById",fetchType = FetchType.EAGER))
})                         
property: user属性   
cloumn:根据uid在user库进行查找   
one=@One(select ="在user库查找的方式")  
fetchType.EAGER:立即加载方式 (还有lazy懒加载,default默认)

一对多(用户查账户)

在User实体类中就应该有一个 private List<Account> accounts; 属性
IUserDao(Interface)
 
@Results(id = "userMap",value = {
        @Result(id = true, column = "id",property = "userId"),//id为主键
        @Result(column = "username",property = "userName"),
        @Result(column = "sex",property = "userSex"),
        @Result(column = "birthday",property = "userBirthday"),
        @Result(column = "address",property = "userAddress"),
        @Result(property = "accounts",column = "id",many =@Many(select = "com.tulun.dao.IAccount.findAccountByUid",fetchType = FetchType.LAZY))
})
property: accounts属性   
cloumn:根据id在account库进行查找   
many=@Many(select ="在account库查找的方式")  
fetchType.LAZY:懒加载方式

缓存的配置

mybatis中不管xml还是注解,一级缓存都是本身具备的.
二级缓存:

 SqlSession sqlSession = factory.openSession();
 User user1 = sqlSession.getMapper(IUserDao.class).findById(1);
 System.out.println(user1);
 sqlSession.close(); //释放一级缓存
 
 SqlSession sqlSession = factory.openSession();// 再次打开sqlSession
 User user2 = sqlSession.getMapper(IUserDao.class).findById(1);
 System.out.println(user2);

使开启二级缓存:
SqlMapConfig.xml文件

<settings>
    <!--配置二级缓存-->
    <setting name="cacheEnabled" value="true"/>
</settings>

IUserDao接口

@CacheNamespace(blocking = true)  //开启二级缓存
public interface IUserDao {
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值