MyBatis(详)

Posted 364.99°

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis(详)相关的知识,希望对你有一定的参考价值。

1. 简介

特性

  • 支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架
  • 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集
  • 可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java
    Objects,普通的Java对象)映射成数据库中的记录
  • 是一个 半自动的ORM(Object Relation Mapping)框架

和其它持久化层技术对比

  • JDBC
    • SQL 夹杂在Java代码中耦合度高,导致硬编码内伤
    • 维护不易且实际开发需求中 SQL 有变化,频繁修改的情况多见
    • 代码冗长,开发效率低
  • Hibernate 和 JPA
    • 操作简便,开发效率高
    • 程序中的长难复杂 SQL 需要绕过框架
    • 内部自动生产的 SQL,不容易做特殊优化
    • 基于全映射的全自动框架,大量字段的 POJO 进行部分映射时比较困难
    • 反射操作太多,导致数据库性能下降
  • MyBatis
    • 轻量级,性能出色
    • SQL 和 Java 编码分开,功能边界清晰。Java代码专注业务、SQL语句专注数据
    • 开发效率稍逊于HIbernate,但是完全能够接受

2. 搭建

1. 依赖

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>x.x.x</version>
</dependency>

2. 核心配置文件

<?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">
<configuration>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="$driver"/>
        <property name="url" value="$url"/>
        <property name="username" value="$username"/>
        <property name="password" value="$password"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

3. 映射文件

<?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="org.mybatis.example.BlogMapper">
  <insert id="insertUser">
    insert into t_user values(null,'admin','123456',23,'男','12345@qq.com')
  </select>
</mapper>

3. mapper接口

public interface UserMapper 
  int insertUser();

4. 测试

//读取MyBatis的核心配置文件
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//创建SqlSessionFactoryBuilder对象 
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//通过核心配置文件所对应的字节输入流创建工厂类SqlSessionFactory,生产SqlSession对象 
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
//创建SqlSession对象,此时通过SqlSession对象所操作的sql都必须手动提交或回滚事务 
//SqlSession sqlSession = sqlSessionFactory.openSession(); 
//创建SqlSession对象,此时通过SqlSession对象所操作的sql都会自动提交 
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//通过代理模式创建UserMapper接口的代理实现类对象 
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//调用UserMapper接口中的方法,就可以根据UserMapper的全类名匹配元素文件,通过调用的方法名匹配 映射文件中的SQL标签,并执行标签中的SQL语句 
int result = userMapper.insertUser(); 
//sqlSession.commit(); 
System.out.println("结果:"+result);
  • SqlSession 代表Java程序和数据库之间的会话。(HttpSession是Java程序和浏览器之间的会话)
  • SqlSessionFactory “生产” SqlSession的 “工厂”

3. 核心配置文件详解

<?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">
<configuration>
    <!--MyBatis核心配置文件中,标签的顺序: 
    	properties?,settings?,typeAliases?,typeHandlers?, objectFactory?,
    	objectWrapperFactory?,reflectorFactory?, 
    	plugins?,environments?,databaseIdProvider?,mappers? 
    -->
    <!--引入properties文件-->
    <properties resource="jdbc.properties" />
    <!--设置类型别名-->
    <typeAliases>
        <!--typeAlias:设置某个类型的别名 
        	属性:
        		type:设置需要设置别名的类型 
        		alias:设置某个类型的别名,若不设置该属性,那么该类型拥有默认的别名,即类名 且不区分大小写 
        -->
        <!--<typeAlias type="com.atguigu.mybatis.pojo.User"></typeAlias>-->
        <!--以包为单位,将包下所有的类型设置默认的类型别名,即类名且不区分大小写-->
        <package name="com.atguigu.mybatis.pojo"/>
    </typeAliases>
    <!--environments:配置多个连接数据库的环境 
    	属性:
    		default:设置默认使用的环境的id 
    -->
    <environments default="development">
        <!--environment:配置某个具体的环境 
        	属性:
        		id:表示连接数据库的环境的唯一标识,不能重复 
        -->
        <environment id="development">
            <!--transactionManager:设置事务管理方式 
            	属性:
            		type="JDBC|MANAGED" 
	            		JDBC:表示当前环境中,执行SQL时,使用的是JDBC中原生的事务管理方式,事务的提交或回滚需要手动处理
	            		MANAGED:被管理,例如Spring 
	        -->
            <transactionManager type="JDBC"/>
            <!--dataSource:配置数据源 
            	属性:
            		type:设置数据源的类型 type="POOLED|UNPOOLED|JNDI" 
	            		POOLED:表示使用数据库连接池缓存数据库连接 
	            		UNPOOLED:表示不使用数据库连接池 
	            		JNDI:表示使用上下文中的数据源 
            -->
            <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">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/ssmserverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!--引入映射文件-->
    <mappers>
        <!--<mapper resource="mappers/UserMapper.xml"/>-->
        <!--以包为单位引入映射文件 
        	要求: 
        		1、mapper接口所在的包要和映射文件所在的包一致 
        		2、mapper接口要和映射文件的名字一致 
        -->
        <package name="com.atguigu.mybatis.mapper"/>
    </mappers>

4. 增删改查

<!--int insertUser();-->
<insert id="insertUser"> 
	insert into t_user values(null,'admin','123456',23,'男') 
</insert>

<!--int deleteUser();-->
<delete id="deleteUser"> 
	delete from t_user where id = 7 
</delete>

<!--int updateUser();-->
<update id="updateUser"> 
	update t_user set username='ybc',password='123' where id = 6 
</update>

<!--User getUserById();-->
<select id="getUserById" resultType="com.atguigu.mybatis.bean.User"> 
	select * from t_user where id = 2 
</select>

<!--List<User> getUserList();-->
<select id="getUserList" resultType="com.atguigu.mybatis.bean.User"> 
	select * from t_user 
</select>
  • 查询的标签select必须设置属性resultTyperesultMap,用于设置实体类和数据库表的映射关系
  • resultType:自动映射,用于属性名和表中字段名一致的情况
  • resultMap:自定义映射,用于一对多或多对一字段名和属性名不一致的情况

5. 获取参数值的两种方式

$ 和 #

  • $ 的本质就是字符串拼接
    # 的本质就是占位符赋值
  • $ 使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号
    # 使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号

1. 单个字面量类型的参数

  • 若mapper接口中的方法参数为单个的字面量类型

  • 此时可以使用 $#任意的名称获取参数的值,注意 $需要手动加单引号

    User getUserByUserName(String username);
    
        <select id="getUserByUserName" resultType="user">
            select * from t_user where username = '$username';
        </select>
    

2. 多个字面量类型的参数

  • 若mapper接口中的方法参数为多个

  • 此时MyBatis会自动将这些参数放在一个map集合中,以**arg0,arg1…**为键,以参数为值;以param1,param2…为键,以参数为值

  • 因此只需要通过$#访问map集合的就可以获取相
    对应的值,注意$需要手动加单引号

    User getLogin(String username,String password);
    
        <!--User getLogin(String username,String password);-->
        <select id="getLogin" resultType="User">
            select * from t_user where username = #arg0 and password = #arg1;
        </select>
    

3. map集合类型的参数

  • 若mapper接口中的方法需要的参数为多个时,此时可以手动创建map集合,将这些数据放在map中

  • 只需要通过$#访问map集合的就可以获取相对应的值,注意$需要手动加单引号

    User checkLogin(Map map);
    
        <select id="checkLogin" resultType="user">
            select * from t_user where username = #username and password = #password;
        </select>
    

4. 实体类类型的参数

  • 若mapper接口中的方法参数为实体类对象时

  • 此时可以使用$#,通过访问实体类对象中的属性名获取属性值,注意$需要手动加单引号

    int insertUser(User user);
    
        <insert id="insertUser">
            insert into t_user values(null,#username,#password,#age,#sex,#email);
        </insert>
    

5. 使用@Param标识参数

  • 可以通过@Param注解标识mapper接口中的方法参数

  • 此时,会将这些参数放在map集合中,以@Param注解的value属性值为键,以参数为值;以param1,param2…为键,以参数为值

  • 只需要通过$#访问map集合的就可以获取相对应的值,注意$需要手动加单引号

    User checkLoginByParam(@Param("username") String username,@Param("password") String password);
    
        <select id="checkLoginByParam" resultType="user">
            select * from t_user where username = #username and password = #password;
        </select>
    

6. MyBatis的各种查询功能

1. 查询一个实体类对象

User getUserById(@Param("id") int id);
<select id="getUserById" resultType="User"> 
	select * from t_user where id = #id 
</select>

2. 查询一个list集合

List<User> getUserList();
<select id="getUserList" resultType="User"> 
	select * from t_user 
</select>
  • 当查询的数据为多条时,不能使用实体类作为返回值,否则会抛出异常TooManyResultsException
  • 但是若查询的数据只有一条,可以使用实体类或集合作为返回值

3. 查询单个数据

int getCount();
<select id="getCount" resultType="_integer"> 
	select count(id) from t_user 
</select>

4. 查询一条数据为map集合

Map<String, Object> getUserToMap(@Param("id") int id);
<!--结果: password=123456, sex=男 , id=1, age=23, username=admin-->
<select id="getUserToMap" resultType="map"> 
	select * from t_user where id = #id 
</select>

5. 查询多条数据为map集合

方式一
List<Map<String, Object>> getAllUserToMap();
<select id="getAllUserToMap" resultType="map"> 
	select * from t_user 
</select>
方式二
@MapKey("id") 
Map<String, Object> getAllUserToMap();
  • @MapKey 设置map集合的键,值是每条数据所对应的 map集合
<!--  
		1=password=123456, sex=男, id=1, age=23, username=admin, 
		2=password=123456, sex=男, id=2, age=23, username=张三, 
		3=password=123456, sex=男, id=3, age=23, username=张三 
-->
<select id="getAllUserToMap" resultType="map"> 
	select * from t_user 
</select>

7. 特殊SQL的执行

1. 模糊查询

List<User> testMohu(@Param("mohu") String mohu);
<select id="testMohu" resultType="User">
    <!--select * from t_user where username like '%$mohu%'-->
    <!--select * from t_user where username like concat('%',#mohu,'%')--> 
	select * from t_user where username like "%"#mohu"%" 
</select>

2. 批量删除

int deleteMore(@Param("ids") String ids);
<delete id="deleteMore"> 
	delete from t_user where id in ($ids) 
</delete>

3. 动态设置表名

List<User> getAllUser(@Param("tableName") String tableName);
<select id="getAllUser" resultType="User"> 
	select * from $tableName
</select>

4. 添加功能获取自增的主键

需求
  • 需求:在插入一条数据后需要获取该条记录的主键
  • 方案
    • 在一个单系统中常见的方法M是设置表中主键为自动递增,每次插入后,mybatis会将自动生成的主键赋值给指定的实体类字段
      • 若数据库支持自动生成主键的字段(比如 MySQLSQL Server),则可以设置useGeneratedKeys=”true”,然后再把keyProperty设置到目标属性上
        (局限性很大、不利于项目后期扩展,实际开发中不推荐使用)

        int insertUser(User user);
        
        <!--int insertUser(User user);-->
        <insert id="insertUser" useGeneratedKeys="true" keyProperty="id"> 
        	insert into 
        		t_user 
        	values(
        		null,
        		#username,
        		#password,
        		#age,
        		#sex) 
        </insert>
        
        @Service
        public class UserService 
            @Autowired
            private UserMapper userMapper;
        
            public int insertUser(User user) 
                return userMapper.insertUser(user);
            
        
        

        useGeneratedKeys设置为true后,mybatis会使用JDBC的getGeneratedkeys方法获取由数据库内部自动生成的主键,并将该值赋值给由keyProperty指定的字段;

      • 对于不支持自增型主键的数据库(例如Oracle),则要先通过序列来模拟自增,每次插入数据前先从序列中拿到自增ID
        (无论是单例项目还是分布式项目都适用)

    • 在分布式系统中,则需要生成全局唯一主键ID

8. 自定义映射resultMap

1. resultMap处理字段和属性的映射关系

<!--resultMap:设置自定义映射 
	属性: 
		id:表示自定义映射的唯一标识 
		type:查询的数据要映射的实体类的类型 
	子标签: 
		id:设置主键的映射关系 
		result:设置普通字段的映射关系
		association:设置多对一的映射关系 
		collection:设置一对多的映射关系 
			属性: 
				property:设置映射关系中实体类中的属性名 
				column:设置映射关系中表中的字段名 
-->
<resultMap id="userMap" type="User">
    <id property="id" column="id"></id>
    <result property以上是关于MyBatis(详)的主要内容,如果未能解决你的问题,请参考以下文章

MyBatis(详)

MyBatis开启驼峰命名法映射作用

mybatis-plus配置返回map自动转换为驼峰

mybatis学习 -每天一记(驼峰命名匹配)

SpringBoot+Mybatis关于开启驼峰映射的设置

Mybatis处理列名—字段名映射— 驼峰式命名映射