根据MyBatis :对象关系映射(ORM,Object Relational Mapping)框架,用于增强jdbc,访问数据库,执行增删改查。
MyBatis 使用步骤:
- 在pom.xml中导入Maven依赖:
- 数据库驱动
- MyBatis依赖
- Druid连接池
- MyBatis主配置文件mybatis.xml:
- 数据库连接
- 指定mapper文件的位置
- Dao接口和Mapper文件
- Dao接口:定义了操作数据的方法
- Mapper文件:sql映射文件,和Dao接口对应的sql语句
- 创建MyBatis的对象SqlSession,通过它的方法执行Sql语句
基本使用
1、在pom.xml中导入Maven依赖:
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>demo-mybatis</artifactId><version>1.0-SNAPSHOT</version><packaging>jar</packaging><dependencies><!-- 数据库驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.22</version></dependency><!-- mybatis依赖 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.6</version></dependency><!-- druid数据库连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.3</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.14</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.1</version><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><encoding>utf-8</encoding><source>1.8</source><target>1.8</target></configuration></plugin></plugins><!-- 资源拷贝插件 --><resources><resource><!-- 指定所在目录 --><directory>src/main/java</directory><includes><!-- 设置要导入的资源文件 --><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource></resources></build></project>
资源拷贝插件:
- 如果将 mapper 文件放在 resources 文件夹下,则不需要配置资源拷贝
- 在将 mapper 文件和 dao 接口中的方法放在一起,则需要配置该插件
2、MyBatis配置文件 resources/mybatis.xml:
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!-- 配置导入 --><properties resource="db.properties"/><!-- 数据库信息的配置 --><environments default="development"><environment id="development"><!-- transactionManager:mybatis的事务类型type:jdbc(表示使用jdbc中的Connection对象的commit、rollback做事务处理)--><transactionManager type="JDBC"/><!-- 数据源类型 --><dataSource type="POOLED"><property name="driver" value="${jdbc.driverClassName}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><!-- 指定sql mapper文件位置 --><mappers><!-- 从类路径开始导入 --><mapper resource="top/songfang/dao/UserMapper.xml"/></mappers></configuration>
resources/db.properties:
jdbc.username=rootjdbc.password=1234jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=truejdbc.driverClassName=com.mysql.cj.jdbc.Driver
3、创建Dao接口:定义了操作数据的方法
public interface UserMapper {// 查询所有数据List<User> selectAll();// 插入数据int insert(User user);}
4、创建对应的UserMapper.xml文件
- dao 接口和 mapper.xml 文件放在同一个文件夹
- dao 接口和 mapper.xml 文件名称一致
- mapper.xml 文件中的 namespace 的值 dao 接口的全限定类名称
- dao 接口中不要使用重载方法,不要使用同名、不同参数的方法
- mapper.xml 文件中的
select id,name,age,male from t_user
<insert id="insert" parameterType="top.songfang.domain.User">insert into t_user(id,name,age,male)values(#{id},#{name},#{age},#{male})</insert>
5、测试:```javapublic class MyBatisUtils {private static SqlSessionFactory sqlSessionFactory;static {// 1、MyBatis配置文件路径String config = "mybatis.xml";try {// 2、从配置文件获取输入流InputStream inputStream = Resources.getResourceAsStream(config);// 3、创建SqlSessionFactory对象sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);} catch (IOException e) {e.printStackTrace();}}// 4、获取SQLSession对象public static SqlSession openSession(){if (sqlSessionFactory != null) {return sqlSessionFactory.openSession();}return null;}public static void main(String[] args) {SqlSession sqlSession = MyBatisUtils.openSession();assert sqlSession != null;UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> users = mapper.selectAll();users.forEach(System.out::println);}}
重要类说明:
- org.apache.ibatis.io.Resources:MyBatis的工具类,用于读取配置文件获取输入流
- SqlSessionFactoryBuilder:用于创建SqlSessionFactory的工厂类
- SqlSessionFactory:重量级资源,是一个接口
- 其默认实现类 DefaultSqlSessionFactory
- 主要用于 SqlSession:SqlSession sqlSession=factory.openSession();
- openSession():无参数,获取的时非自动提交事务的SqlSession对象
- openSession(boolean):true,获取自动提交事务的SqlSession对象;false,非自动提交事务的SqlSession对象
- SqlSession:接口
- 其默认实现类:DefaultSqlSession
- 定义了操作数据的方法,例如selectOne()、selectList()、insert()、update()、delete()、commit()、rollback()等
- SqlSession不是线程安全的,需要在方法内部使用,在执行sql语句之前使用openSession()获取SqlSession,在执行完毕后应及时关闭它sqlSession.close()
参数传递
参数传递是指从 java 代码中把实际的值传到 mapper 文件中,参数类型可以使用 parameterType 进行指定
为了以后可能的使用场景,MyBatis 通过内置的 jdbcType 枚举类型支持下面的 JDBC 类型:
BITFLOATCHARTIMESTAMPOTHERUNDEFINEDTINYINTREALVARCHARBINARYBLOBNVARCHARSMALLINTDOUBLELONGVARCHARVARBINARYCLOBNCHARINTEGERNUMERICDATELONGVARBINARYBOOLEANNCLOBBIGINTDECIMALTIMENULLCURSORARRAY1、单个参数:#{任意字符}
UserMapper接口:public interface UserMapper {// 通过传入的id查询UserUser selectById(int id);}
UserMapper.xml:
- 只有一个参数时可以在select标签中通过parameterType指定传入的参数的类型,参数类型支持类的全限定名(建议)和别名,但是一般可以省略不写
- 只有一个参数时通过 #{任意字符} 来获取传入参数的值,一般为了可读性,与Mapper接口中方法的参数名保持一致
<select id="selectById" parameterType="java.lang.Integer" resultType="top.songfang.domain.User">select id,name,age,male from t_userwhere id = #{id}</select>
2、多个参数:支持三种方式
- 在Mapper.xml文件中根据在方法中的位置进行获取,有两种获取规则
- 使用 @Param 注解在Mapper接口的方法的参数前自定义名称,然后在Mapper.xml文件中通过 #{名称} 获取【建议使用】
UserMapper接口:
// 不使用@Param指定参数名称,使用参数位置进行获取public interface UserMapper {// 通过id或name进行查找List<User> selectByIdAndName(Integer id,String name);}// 使用@Param自定义参数名称public interface UserMapper {// 通过id或name进行查找List<User> selectByIdAndName(@Param("id") Integer id, @Param("name") String name);}
UserMapper.xml:
- 参数类型指定:支持在 #{paramName , javaType= , jdbcType= } 中通过 javaType(全限定类名) 和 jdbcType 来分别指定传入参数的 java 类型和 jdbc 类型,如 #{name , javaType=java.lang.String , jdbcType=VARCHAR}
- 由于 MyBatis 能够通过反射自动推断获取参数的类型,一般在使用时不用指定类型 ```xml
3、多个参数:使用对象进行传参- 将对象作为参数传入,使用对象中的属性来传递具体的参数值,语法 #{属性名 , javaType=类型名称 , jdbcType=数据类型}- javaType:java中属性数据类型,使用全限定名- jdbcType:在数据库中的数据类型,在mybatis中定义了一个jdbcType的枚举类中- JDBC 要求,如果一个列允许使用 null 值,并且会使用值为 null 的参数,就必须要指定 JDBC 类型(jdbcType)- 支持自定义类型处理:#{age , javaType=int , jdbcType=NUMERIC , typeHandler=MyTypeHandler},实现 TypeHandler 接口- 在update标签中使用parameterType="类的全限定名"指定传入对象的类型UserMapper接口:```javapublic interface UserMapper {// 通过id更新用户数据,返回值为本次事务影响的数据库行数int update(User user);}
UserMapper.xml 文件:
<update id="update" parameterType="top.songfang.domain.User">update t_userset name=#{name},age=#{age},male=#{male}where id=#{id}</update>
4、多个参数,使用 Map 进行传参
- 类似使用对象传参的方式,使用 #{map中的key名} 来传参
UserMapper接口:
public interface UserMapper {// 通过Map进行传参int insertUser(Map<String,Object> map);}
UserMapper.xml:
<insert id="insertUser">insert into t_user(id,name,age,male)values (#{id},#{name},#{age},#{male})</insert>
测试:
public class MyBatisUtils {private static SqlSessionFactory sqlSessionFactory;static {// 1、MyBatis配置文件路径String config = "mybatis.xml";try {// 2、从配置文件获取输入流InputStream inputStream = Resources.getResourceAsStream(config);// 3、创建SqlSessionFactory对象sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);} catch (IOException e) {e.printStackTrace();}}// 4、获取SQLSession对象public static SqlSession openSession(){if (sqlSessionFactory != null) {return sqlSessionFactory.openSession();}return null;}public static void main(String[] args) {SqlSession sqlSession = MyBatisUtils.openSession();assert sqlSession != null;UserMapper mapper = sqlSession.getMapper(UserMapper.class);int i = mapper.insertUser(new HashMap<String, Object>() {{put("id",5);put("name", "王五");put("age", 18);put("male", false);}});sqlSession.commit();sqlSession.close();}}
$ 和 # 的区别:
{} 占位符,告诉 MyBatis 使用实际的参数值代替,并使用 PreparedStatement 对象执行 sql 语句,#{…} 代替 sql 语句的 ?【首选】
- 不会有 sql 注入的风险,安全性较高
- 进行了预处理,效率较高
- ${} 占位符,只会做字符串的替换,不会修改或者转义该字符串,有 sql 注入的风险,安全性低,效率低
- ${} 占位符在一般用于元数据(如表名、列名、不同列排序等)动态生成时十分有用
- 比如:order by ${columnName},MyBatis 就不会修改或转义该字符串
UserMapper接口:
public interface UserMapper {// 可以自定义查询的列和查询值User findByColumn(@Param("column") String column, @Param("value") String value);}
UserMapper.xml:
- ${column} 会直接被替换
{value} 会使用 ? 预处理
<select id="findByColumn" resultType="top.songfang.domain.User">select id,name,age,male from t_userwhere ${column} = #{value}</select>
like 子句:有多种写法
public interface UserMapper {// 可以自定义查询的列和查询值List<User> find(@Param("pattern") String pattern);}
1、用 java 代码指定 like 的内容
<select id="find" resultType="top.songfang.domain.User">select id,name,age,male from t_userwhere name like #{pattern}</select>
测试:
List<User> users = userMapper.find("%王%");users.forEach(System.out::println);
2、在 mapper 中拼接 like 的内容
{} 在解析成 sql 语句的时候,会在变量外侧自动加单引号,所以%需要使用双引号
测试:<select id="find" resultType="top.songfang.domain.User">select id,name,age,male from t_userwhere name like "%" #{pattern} "%"</select>
3、使用 contact 内部函数List<User> users = userMapper.find("王");users.forEach(System.out::println);
4、使用 mybatis 的 bind 标签<select id="find" resultType="top.songfang.domain.User">select id,name,age,male from t_userwhere name like CONCAT("%",#{pattern},"%")</select>
bind 标签可以使用 OGNL 表达式以外创建一个变量并将其绑定到上下文中
<select id="find" resultType="top.songfang.domain.User"><bind name="pattern" value=" '%' + pattern + '%' "/>select id,name,age,male from t_userwhere name like #{pattern}</select>
结果映射
MyBatis 执行了 sql 语句,得到了 java 对象:resultMap和resultType二选一
处理方式:
- mybatis 执行 sql 语句,然后 mybatis 调用类的无参数构造方法,创建对象
- mybatis 把 ResultSet 指定列值付给同名的属性
ResultSet rs = executeQuery("select id,name,age,male from t_user");while (rs.next()) {User user = new User();user.setId(rs.getInt("id"));user.setName(rs.getString("name"));user.setAge(rs.getInt("age"));user.setMale(rs.getBoolean("male"));}
- resultType:sql 执行完毕后,数据转换为 javaBean 或 POJO 领域模型 ,java 类型是任意的
- resultType:类的全限定名
- resultType:类型的别名,如 java.lang.Integer 别名是 int
- resultMap:可以自定义 sql 的结果和 java 对象属性的映射关系,更灵活的把列值赋值给指定属性,常用在列名和java对象属性名不一致的情况
- 先定义 resultMap ,指定列名和属性的对应关系
- 在
