MyBatis-基本语法
MyBatis-基本语法
啃不动地大坚果 发表于9个月前
MyBatis-基本语法
  • 发表于 9个月前
  • 阅读 42
  • 收藏 0
  • 点赞 0
  • 评论 0

【腾讯云】新注册用户域名抢购1元起>>>   

----------------------------------------------------------
第一节 MyBatis生命周期
1.MyBatis的基本构成
SqlSessionFactoryBuilder(构造器) > SqlSessionFactory(工厂接口 单例) > SqlSession (> SqlMapper)

2.获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

3.创建SqlSession
1)SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.Commit();

2)通过命名信息直接获取
MYPojo mypojo = sqlSession.selectOne("com.wdw.m1.MYPojoMapper.getAllData", 3);
3)通过映射器获取
MYPojoMapper myPojoMapper = sqlSession.getMapper(MYPojoMapper.class);
List<MYPojo> lstmyPojo = myPojoMapper.getAllData(1);

4.映射器Mapper
1)首先创建java接口
2)创建xml文件
<mapper namespace="com.wdw.m1.MYPojoMapper">
    <select id="getAllData" resultMap="MYPojo" >
        select * from tb_item_param WHERE id = #{id} and item_cat_id = #{item_cat_id}
    </select>
</mapper>

5.close SqlSession

----------------------------------------------------------
第二节 MyBatis配置文件解析

1.MYbatis配置文件

<configuration>
    <properties></properties><!-- 属性 -->
    <settings></settings><!-- 设置 -->
    <typeAliases></typeAliases><!-- 类型命名 -->
    <typeHandlers></typeHandlers><!-- 类型处理器 -->
    <objectFactory type=""></objectFactory><!-- 对象工厂 -->
    <plugins></plugins><!-- 插件 -->
    <environments default=""><!-- 配置环境 -->
        <environment id=""><!-- 环境 id-->
            <transactionManager type=""></transactionManager><!-- 事物管理器 -->
            <dataSource type=""></dataSource><!-- 数据源 -->
        </environment>
    </environments>
    <databaseIdProvider type=""></databaseIdProvider><!-- 数据库厂商标识 -->
    <mappers></mappers><!-- 映射器 -->
</configuration>

2.properties
1)property子元素
<properties>
    <property name="jdbc.driver" value="com.mysql.jdbc.Driver"/>
    <property name="jdbc.url" value="jdbc:mysql://:3306/s1?allowMultiQueries=true"/>
</properties>
2)resource文件引入
<properties resource="dbconfig.properties"></properties>
3)优先级
a.首先读取<property>标签中定义的属性
b.读取resource文件中配置的属性 覆盖之前取得的值
c.读取方法参数中指定的属性 覆盖之前取得的值

3.settings
cacheEnabled 全局二级缓存
lazyLoading 延迟加载开关 可以使用fetchType具体到某一个查询

<settings>
    <setting name="cacheEnabled" value="true"/>
    <setting name="logImpl" value="STDOUT_LOGGING" />
</settings>

4.typeAliases别名
<typeAliases>
    <typeAlias alias="Driver" type="com.mysql.jdbc.Driver"/>
    <package name="com.mysql.jdbc"/>类数量很多的时候可以使用package批量指定别名 即默认为类名的全小写
</typeAliases>

5.environments配置环境

<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC">
        <property name=autoCommit" value="false"/>
    </transactionManager>
      <dataSource type="POOLED">
      <property name="driver" value="${jdbc.driver}"/>
      <property name="url" value="${jdbc.url}"/>
      <property name="username" value="${jdbc.username}"/>
      <property name="password" value="${jdbc.password}"/>
    </dataSource>
  </environment>
  <environment id="test">
      ...
  </environment> 
</environments>

1)default指明要使用的环境ID
2)transactionManager 有3种type
JDBC JDBC方式管理事物
MANAGEN 不提交或回滚一个连接、让容器来管理事务的整个生命周期 JNDI等
自定义 
3)dataSource有四种方式
UNPOOLED 不使用连接池
POOLED 连接池数据库
JNDI JNDI数据源
自定义数据源 
通常我们会使用第三方连接池插件 需要实现DataSourceFactory接口
并要指定全类名<dataSource type="com.XXX.XXX.XXX">
4)在代码中可以指定是否自动提交
sqlSessionFactory.openSession(true)自动提交
sqlSessionFactory.openSession(false)不自动提交

6.mappers
<mappers>
  <package name="com.wdw.m1"/>
  <mapper class="com.wdw.m1.MYPojoMapper"/>
  <mapper resource="MyPojo.xml"/>
  <mapper url="file:///com/wdw/m1/MyPojo.xml"/>
</mappers>

----------------------------------------------------------
第三节 MyBatis映射器文件解析
cache –命名空间的二级缓存配置
cache-ref – 其他命名空间缓存配置的引用。
resultMap – 自定义结果集映射
parameterMap – 已废弃!老式风格的参数映射
sql –抽取可重用语句块。
insert – 映射插入语句
update – 映射更新语句
delete – 映射删除语句
select – 映射查询语句

<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapper">
    <select id="getJoinDataAss" resultType="com.wdw.m1.MYPojo2">
        select t2.* from tb_item_param_item t2 where t2.id= #{id} and t2.lastName= #{lastName}
    </select>
     <select id="getEmpByIdReturnMap" resultType="map">
         select * from tbl_employee where id=#{id}
     </select>
    <insert id="insData">
        insert into tb_item_param(item_cat_id,param_data,created,updated) 
            values(#{item_cat_id},#{param_data},#{created},#{updated});
    </insert>
    <update id="updData">
        update tb_item_param 
           set param_data = #{param_data},
           updated = #{updated}
         where id= #{id}
    </update>
    <delete id="delData">
        delete from tb_item_param where id= #{id}
    </delete>
</mapper>

1.指定参数名
1)直接指定参数#{id}
public Employee getEmpByIdAndLastName(@Param("id")Integer id,@Param("lastName")String lastName);
不用@Param("id")指定时 默认参数名为param1,param2,paramN
2)用map指定参数
public Employee getEmpByMap(Map<String, Object> map);
3)用对象指定参数
public Long addEmp(Employee employee);
4)使用List set 数组 指定参数
public Long addEmp(List list);
public Long addEmp(Set set);
public Long addEmp(int[] array);
5)数据的取得
mybatis内部处理参数时
单个参数:mybatis不会做特殊处理,
    #{参数名/任意名}:取出参数值。
    
多个参数:mybatis会将其封装成 一个map,
    key:param1...paramN,或者参数的索引也可以
    value:传入的参数值
    用#{param1}就是从map中取出数据
用map指定参数时 使用#{key}取出数据
用对象指定参数时 使用#{对象.属性名}取出数据
用List set 数组 指定参数时 使用#{list0}#{set0}#{array0}取出数据

mybatis有两个默认内置参数:
_parameter:代表整个参数
    单个参数:_parameter就是这个参数
    多个参数:参数会被封装为一个map;_parameter就是代表这个map
_databaseId:如果配置了databaseIdProvider标签。
    _databaseId就是代表当前数据库的别名oracle

6)返回值类型
a.返回一条记录的map;key就是列名,值就是对应的值
public Map<String, Object> getEmpByIdReturnMap(Integer id);
b.多条数据用map封装时 指定key值
@MapKey("lastName")
public Map<String, Employee> getEmpByLastNameLikeReturnMap(String lastName);

2.resultMap

<resultMap type="com.atguigu.mybatis.bean.Employee" id="MySimpleEmp">
    <!--指定主键列的封装规则
    id定义主键会底层有优化;
    column:指定哪一列
    property:指定对应的javaBean属性
      -->
    <id column="id" property="id"/>
    <!-- 定义普通列封装规则 --><!-- 其他不指定的列会自动封装 -->
    <result column="did" property="dept.id"/>
</resultMap>

<!-- resultMap:自定义结果集映射规则;  -->
<!-- public Employee getEmpById(Integer id); -->
<select id="getEmpById"  resultMap="MySimpleEmp">
    select tbl_employee.*,tbl_dept.id as did 
      from tbl_employee,tbl_dept 
     where tbl_employee.id=#{id} 
       and tbl_employee.deptid=tbl_dept.id
</select>

3.association
1)分段查询

<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmpByStep">
    <id column="id" property="id"/>
    <result column="last_name" property="lastName"/>
    <result column="email" property="email"/>
    <result column="gender" property="gender"/>
    <!-- association定义关联对象的封装规则
        select:表明当前属性是调用select指定的方法查出的结果
        column:指定将哪一列的值传给这个方法
        流程:使用select指定的方法(传入column指定的这列参数的值)查出对象,
        并封装给property指定的属性
     -->
    <association property="dept" 
        select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById"
        column="d_id"> 
    <!-- coloumn为检索条件 当有多个检索条件时 
         column="{key1=column1,key2=column2}"-->
    </association>
</resultMap>
<select id="getEmpByIdStep" resultMap="MyEmpByStep">
    select * from tbl_employee where id=#{id}
</select>

4.collection
1)嵌套结果集 即POJO中某个属性为1:N的集合类型

<resultMap type="com.atguigu.mybatis.bean.Department" id="MyDept">
    <id column="did" property="id"/>
    <result column="dept_name" property="departmentName"/>
    <!-- 
        collection定义关联集合类型的属性的封装规则 
        ofType:指定集合里面元素的类型
    -->
    <collection property="emps" ofType="com.atguigu.mybatis.bean.Employee">
        <!-- 定义这个集合中元素的封装规则 -->
        <id column="eid" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="email" property="email"/>
        <result column="gender" property="gender"/>
    </collection>
</resultMap>


2)collection分段查询

<resultMap type="com.atguigu.mybatis.bean.Department" id="MyDeptStep">
    <id column="id" property="id"/>
    <id column="dept_name" property="departmentName"/>
    <collection property="emps" 
        select="com.atguigu.mybatis.dao.EmployeeMapperPlus.getEmpsByDeptId"
        column="{deptId=id}" fetchType="lazy"></collection>
</resultMap>

column为检索条件 当有多个检索条件时 column="{key1=column1,key2=column2}"
fetchType="lazy":表示使用延迟加载;- lazy:延迟- eager:立即

5.主键自增
1)useGeneratedKeys="true";使用自增主键获取主键值策略 keyProperty;指定对应的主键属性

<insert id="addEmp" parameterType="com.atguigu.mybatis.bean.Employee"
    useGeneratedKeys="true" keyProperty="id" databaseId="mysql">
    insert into tbl_employee(last_name,email,gender) 
    values(#{lastName},#{email},#{gender})
</insert>

2)Oracle不支持自增;Oracle使用序列来模拟自增

<insert id="addEmp" databaseId="oracle">
    <!-- 
    keyProperty:查出的主键值封装给javaBean的哪个属性
    order="BEFORE":当前sql在插入sql之前运行 AFTER:当前sql在插入sql之后运行
    resultType:查出的数据的返回值类型
    -->
    <selectKey keyProperty="id" order="BEFORE" resultType="Integer">
        <!-- 编写查询主键的sql语句 -->
        <!-- BEFORE-->
        select EMPLOYEES_SEQ.nextval from dual 
        <!-- AFTER:
        select EMPLOYEES_SEQ.currval from dual -->
    </selectKey>
    
    <!-- 插入时的主键是从序列中拿到的 -->
    insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL) 
    values(#{id},#{lastName},#{email}) 
</insert>

----------------------------------------------------------
第四节 MyBatis 表达式与动态sql
1)表达式
if
choose (when, otherwise)
trim (where, set)
    prefix=""          前缀 prefix给拼串后的整个字符串加一个前缀 
    prefixOverrides="" 前缀覆盖: 去掉整个字符串前面多余的字符
    suffix=""          后缀 suffix给拼串后的整个字符串加一个后缀 
    suffixOverrides="" 后缀覆盖:去掉整个字符串后面多余的字符
foreach
    collection:指定要遍历的集合:list类型的参数会特殊处理封装在map中,map的key就叫list
    item:将当前遍历出的元素赋值给指定的变量
    separator:每个元素之间的分隔符
    open:遍历出所有结果拼接一个开始的字符
    close:遍历出所有结果拼接一个结束的字符
    index:索引。遍历list的时候是index就是索引,item就是当前值
          遍历map的时候index表示的就是map的key,item就是map的值

2)动态sql标签
<where><set><bind>

3)可抽取的sql片段
<sql id="insertColumn">
    employee_id,last_name,email
</sql>
sql片段取得
<include refid="insertColumn"></include>

4)示例

<!-- where -->
<select>
	select * from tbl_employee
	<where>
	  <if test="id!=null">
	     id=#{id}
	  </if>
	  <if test="lastName!=null and lastName!=''">
	     and last_name like #{lastName}
	  </if>
	  <if test="gender==0 or gender==1">
	      and gender=#{gender}
	  </if>
	</where>
</select>
<!-- trim -->
<select>
	select * from tbl_employee
	<trim prefix="where" suffixOverrides="and">
	   <if test="id!=null">
	       id=#{id} and
	   </if>
	   <if test="lastName!=null and lastName!=''">
	       last_name like #{lastName} and
	   </if>
	   <if test="gender==0 or gender==1">
	        gender=#{gender}
	   </if>
	</trim>
</select>
<!-- choose -->
<select>
	select * from tbl_employee 
	<where>
	    <choose>
	        <when test="id!=null">
	            id=#{id}
	        </when>
	        <when test="email!=null">
	            email = #{email}
	        </when>
	        <otherwise>
	            gender = 0
	        </otherwise>
	    </choose>
	</where>
</select>
<!-- set -->
<update>
	<set>
	    <if test="lastName!=null">
	        last_name=#{lastName},
	    </if>
	    <if test="email!=null">
	        email=#{email},
	    </if>
	    <if test="gender!=null">
	        gender=#{gender}
	    </if>
	</set>
	where id=#{id} 
</update>
<!-- foreach -->
<!--public List<Employee> getEmpsByConditionForeach(List<Integer> ids);  -->
<select id="getEmpsByConditionForeach" 
        resultType="com.atguigu.mybatis.bean.Employee">
    select * from tbl_employee
    <!--
        collection:指定要遍历的集合:list类型的参数会特殊处理封装在map中,map的key就叫list
        item:将当前遍历出的元素赋值给指定的变量
        separator:每个元素之间的分隔符
        open:遍历出所有结果拼接一个开始的字符
        close:遍历出所有结果拼接一个结束的字符
        index:索引。遍历list的时候是index就是索引,item就是当前值
                      遍历map的时候index表示的就是map的key,item就是map的值
        
        #{变量名}就能取出变量的值也就是当前遍历出的元素
      -->
    <foreach collection="ids" item="item_id" separator=","
        open="where id in(" close=")">
        #{item_id}
    </foreach>
</select>


<!-- 批量保存 -->
<!--public void addEmps(@Param("emps")List<Employee> emps);  -->
<!--MySQL下批量保存:可以foreach遍历   mysql支持values(),(),()语法-->
<insert id="addEmps">
    insert into tbl_employee(
        <include refid="insertColumn"></include>
    )
    values
    <foreach collection="emps" item="emp" separator=",">
        (#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
    </foreach>
</insert>
<!-- Oracle数据库批量保存: 
Oracle不支持values(),(),()
Oracle支持的批量方式 多个insert放在begin - end里面
begin
    insert into employees(employee_id,last_name,email) 
    values(employees_seq.nextval,'test_001','test_001@atguigu.com');
    insert into employees(employee_id,last_name,email) 
    values(employees_seq.nextval,'test_002','test_002@atguigu.com');
end;-->
<insert id="addEmps" databaseId="oracle">
    <foreach collection="emps" item="emp" open="begin" close="end;">
        insert into employees(employee_id,last_name,email) 
            values(employees_seq.nextval,#{emp.lastName},#{emp.email});
    </foreach>
</insert>

----------------------------------------------------------
第五节 MyBatis缓存
MyBatis的两级缓存:
1.一级缓存:(本地缓存):sqlSession级别的缓存。一级缓存是一直开启的。
        与数据库同一次会话期间查询到的数据会放在本地缓存中。
        以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库;

        一级缓存失效情况(没有使用到当前一级缓存的情况,效果就是,还需要再向数据库发出查询):
        1、sqlSession不同。
        2、sqlSession相同,查询条件不同.(当前一级缓存中还没有这个数据)
        3、sqlSession相同,两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响)
        4、sqlSession相同,手动清除了一级缓存(缓存清空)
           sqlSession.clearCache()但只能呢个清除一级缓存 无法清除二级缓存

2.二级缓存:(全局缓存):基于namespace级别的缓存:一个namespace对应一个二级缓存:
        工作机制:
        1、一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中;
        2、如果会话关闭;一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,就可以参照二级缓
             存中的内容;只有在会话提交或者关闭后才会保存到二级缓存
        3、不同namespace查出的数据会放在自己对应的缓存中(map)
            效果:数据会从二级缓存中获取
                查出的数据都会被默认先放在一级缓存中。
                只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中
        使用:
            1)、开启全局二级缓存配置:<setting name="cacheEnabled" value="true"/>
            2)、去mapper.xml中配置使用二级缓存:
                <cache></cache>
            3)、二级缓存的POJO需要实现序列化接口
3)和缓存有关的设置/属性:
            1)、cacheEnabled=true:false:关闭缓存(二级缓存关闭)(一级缓存一直可用的)
            2)、每个select标签都有useCache="true":
                    false:不使用缓存(一级缓存依然使用,二级缓存不使用)
            3)、【每个增删改标签的:flushCache="true":(一级二级都会清除)】
                    增删改执行完成后就会清楚缓存;
                    测试:flushCache="true":一级缓存就清空了;二级也会被清除;
                    查询标签:flushCache="false":
                        如果flushCache=true;每次查询之后都会清空缓存;缓存是没有被使用的;
            4)、sqlSession.clearCache();只是清楚当前session的一级缓存;
            5)、localCacheScope:本地缓存作用域:(一级缓存SESSION);当前会话的所有数据保存在
                 会话缓存中;STATEMENT:可以禁用一级缓存;

  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 3
博文 78
码字总数 43391
×
啃不动地大坚果
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: