Mybatis——Mybatis初级知识

Mybais

1.Mybatis的使用

数据库的配置此处省略,配置方法很多种。

@Configuration
@PropertySource("data.yml")
public class Config {

    // 注入数据源对象
    @Bean
    public DataSource dataSource(DatabaseParam databaseParam){
        PooledDataSource pooledDataSource = new PooledDataSource();
        pooledDataSource.setUsername(databaseParam.getUsername());
        pooledDataSource.setPassword(databaseParam.getPassword());
        pooledDataSource.setDriver(databaseParam.getDriver());
        pooledDataSource.setUrl(databaseParam.getUrl());
        return pooledDataSource;
    }

    // 创建一个sqlSessionFactoryBean对象
    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource ds) throws IOException {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(ds); // 配置数据源
        sqlSessionFactoryBean.setTypeAliasesPackage("cn.zl.model"); // 设置实体类别名
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:/mapper/mybatis.xml"));
        return sqlSessionFactoryBean;
    }

编写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">
<!-- namespace:理解成实现类的全路径(包名+类名) -->
<mapper namespace="cn.zl.mapper">
    <!--  id:方法名
       ParameterType:定义参数类型
       resultType:返回值类型

       如果方法返回值是 list,在resultType 中写List泛型,
       因为mybatis对jdbc封装,一行一行读取数据
     -->
    <select id="selAll" resultType="cn.zl.model.City">
     select * from city;
  </select>
</mapper>

测试代码:

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
   SqlSessionFactory sqlSessionFactory = applicationContext.getBean(SqlSessionFactory.class);
  // 之前已经把SQLSessionFactorybean注入到Spring容器中了,所以可以直接获取sqlSessionFactory对象.
  SqlSession sqlSession = sqlSessionFactory.openSession();
  List<City> objects = sqlSession.selectList("cn.zl.mapper.selAll");
  objects.forEach(k->{
   System.out.println(k);
  });

2.Mybatis的工作原理

  1. 创建sqlSessionFactory对象负载加载配置文件,解析mapp.xml 文件,会存放在configuration中。
  2. 创建sqlSession对象,此对象负责创建Executor对象与事务。
  3. 调用api查询,最终会调用Executor对象的API,调用Executor之前,会创建一个MappedStatement对象,此对象封装了映射信息。
  4. 然后创建StatementHandler来解析参数创建一个prepareStatement,并且调用query方法。
  5. 最后通过resultSetHandler对象来对查询出来的数据进行解析。

3.#{}和${}的区别

  1. #{} 是占位符,进行预处理,通过PreparedStatement 来处理。mybatis首先会将{}替换成?,调用PreparedStatement.set方法来进行赋值处理。可以防止sql注入。会根据类型自动加上单引号。
  2. ${} 没有预处理,通过Statement 来处理,只是进行简单的字符串替换。不会给数据加单引号。

4.mybatis传入参数

可以在SQLSessionFactoryBean 中设置别名。

4.1 顺序传入参数

<?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="cn.zl.dao.CityDao">

  </select>
    <!-- 循序传入参数  此处必须要用param1,param2 或者arg1, arg0 -->
    <select id="queryOne" resultType="City">
    select * from city where id = #{param1} and city_code = #{param2}
    </select>
</mapper>

注意这里按参数名去引用的话会报如下错误,mybatis错误提示很细致,这里明确给我们提示,匿名参数只能使用
arg1, arg0, param1, param2 类似的形式
这种传参方式的缺点是不够灵活,必须严格按照参数顺序来引用

4.2 使用@Param注解

<?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">
<!-- namespace:理解成实现类的全路径(包名+类名) -->
<mapper namespace="cn.zl.dao.CityDao">

    <select id="queryOneParam" resultType="City">
    select * from city where id = #{id} and city_code = #{city_code}
    </select>
</mapper>

dao层编写

@Repository
public interface CityDao {
    City queryOneParam(@Param("id") int id ,@Param("city_code") int city_code);
}

4.3 使用Map传递参数

<?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">
<!-- namespace:理解成实现类的全路径(包名+类名) -->
<mapper namespace="cn.zl.dao.CityDao">
    <select id="queryOneMap" parameterType="Map" resultType="City" >
    select * from city where id = #{id} and city_code = #{city_code}
    </select>
</mapper>

dao层编写

@Repository
public interface CityDao {
    City queryOneMap(Map map);
}

测试

HashMap map = new HashMap<>();
map.put("id",344);
map.put("city_code",710800);
City cities = cityService.queryOneMap(map);

4.4 java bean传递多个参数

编写参数类

@Component
@Data
public class Param {
    private int id;
    private int city_code;
}

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">
<!-- namespace:理解成实现类的全路径(包名+类名) -->
<mapper namespace="cn.zl.dao.CityDao">
    <select id="queryOneObject" parameterType="Param" resultType="City" >
    select * from city where id = #{id} and city_code = #{city_code}
    </select>
</mapper>

dao

@Repository
public interface CityDao {
    City queryOneObject(Param param);
}

测试

Param param = new Param();
param.setId(344);
param.setCity_code(710800);
cityService.queryOneObject(param);

4.5 直接使用JSON传递参数

xml

<select id="findByJSONObject" resultType="City" parameterType="com.alibaba.fastjson.JSONObject" >
    select * from city where id = #{id} and city_code = #{city_code}
    </select>

dao

City findByJSONObject(JSONObject json);

测试

JSONObject jsonObject = new JSONObject();
jsonObject.put("id",344);
jsonObject.put("city_code",710800);
cityService.equals(jsonObject);

4.6 传递集合类型参数List、Set、Array

在一些复杂查询中,比如说in,无法使用静态sql,这个时候必须要用到动态sql

 <select id="findByList" resultType="City">
    select * from city where id in
    <foreach collection="list" open="(" separator="," close=")" item="id">
        #{id}
    </foreach>
 </select>

dao层

 List<City> findByList(List<Integer> ids);

测试

ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
List<City> byList = cityService.findByList(list);

foreach元素的属性主要有 item,index,collection,open,separator,close。
item表示集合中每一个元素进行迭代时的别名,
index指定一个名字,用于表示在迭代过程中,每次迭代到的位置,
open表示该语句以什么开始,
separator表示在每次进行迭代之间以什么符号作为分隔符,
close表示以什么结束
在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的,主要有一下3种情况:
1.如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
2.如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
3.如果传入的参数是多个的时候,我们就需要把它们封装成一个Map或者Object

4.7 参数类型为对象+集合

编写一个参数类

@Data
public class MapParam {
    List<Integer> ids;
}

xml

<select id="findByDepartment" resultType="City" parameterType="cn.zl.model.MapParam">
        select * from city where id in
        <foreach collection="mapParam.ids" open="(" separator="," close=")" item="id">
            #{id}
        </foreach>
    </select>

dao

List<City> findByDepartment(@Param("mapParam") MapParam param);

测试

ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
MapParam mapParam = new MapParam();
mapParam.setIds(list);
List<City> byDepartment = cityService.findByDepartment(mapParam);

5.mybatis结果映射

结果映射分为两种,一种是resultTypeType,resultType。
resultType可以把查询结果封装到pojo类型中,但必须pojo类的属性名和查询到的数据库表的字段名一致。
如果sql查询到的字段与pojo的属性名不一致,则需要使用resultMap将字段名和属性名对应起来,进行手动配置封装,将结果映射到pojo中
针对resultType举例

<mapper namespace="cn.zl.dao.CityDao">

    <resultMap id="map1" type="City">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="cityCode" property="city_code"/>
        <result column="provinceCode" property="province_code"/>
    </resultMap>
    <select id="getAllCity" resultMap="map1">
     select * from city;
  </select> 
</mapper>

6. mybatis 的缓存

mybatis缓存分为一共分为两级,说实话很鸡肋。redis不是更好吗?

6.1 一级缓存

默认开启一级缓存,同一个 SqlSession 对象, 在参数和 SQL 完全一样的情况下, 只执行一次 SQL 语句(如果缓存没有过期)
可以通过flushCache=“true” 设置主动刷新缓存。

  1. 在同一个sqlSession 中,Mybatis 会把执行的方法和参数算法生产缓存的key,将key和结果放在一个map中,如果后续的key一样,则直接从Map中获取数据。
  2. 不同的sqlSession 之前的缓存是相互隔离的。
  3. 用一个sqlSession,可以通过配置使得查询前清空缓存;
  4. 任何的 UPDATE, INSERT, DELETE 语句都会清空缓存。

6.2 二级缓存

二级缓存存在于 SqlSessionFactory 生命周期中。默认是关闭的。
二级缓存是sqlSessionFactory(mapper)级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是可以横跨SqlSession的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值