Java框架学习:MyBatis之MyBatis入门、优化配置、Mapper映射文件

文章目录

      • ORM
      • MyBatis入门
        • 第一个MyBatis程序
      • 优化配置
        • 读取配置文件获取数据库连接的参数
        • 日志配置
      • Mapper映射文件

ORM

对象关系映射(Object Relational Mapping,简称ORM)是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。

具体表现:
O - Java对象
R - 数据库表
M - 映射文件
一个Java类对应数据库中的一张表;一个Java对象对应数据库表中的一条数据;Java对象的属性对应数据库表的列。
而这种对应关系通过映射(Mapping)来实现

MyBatis入门

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。

第一个MyBatis程序

存在一张数据库表user,相当于ORM中的“R”,建表语句如下:

CREATE TABLE `user` (
  id int(11) NOT NULL AUTO_INCREMENT,
  username varchar(20) DEFAULT NULL,
  password varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

第一步需要导入依赖


<dependency>
    <groupId>org.mybatisgroupId>
    <artifactId>mybatisartifactId>
    <version>3.4.6version>
dependency>

<dependency>
    <groupId>mysqlgroupId>
    <artifactId>mysql-connector-javaartifactId>
    <version>5.1.18version>
dependency>

第二步创建一个配置文件"mybatis-config.xml"



<configuration>
    <environments default="development">
        <environment id="development">
            
            <transactionManager type="JDBC"/>
            
            <dataSource type="POOLED">
                
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis_db?serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="123"/>
            dataSource>
        environment>
    environments>
    
    <mappers>
        <mapper resource="com/young/mapper/UserMapper.xml"/>
    mappers>
configuration>
mybatis-config.xml映射文件解析:
XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务
管理器(TransactionManager)。
environment元素体中包含了事务管理和连接池的配置。在environments标签中设置default属性指定默认使用的数据库连接环境(environment)
mappers 元素则包含了一组映射器(mapper),这些映射器的 XML 映射文件包含了 SQL 代码和映射定义信息。

创建实体类User,相当于ORM中的“O”

public class User {
	//注意实体类中的属性名称需要与数据库表中列名一一对应
    private Integer id;
    private String username;
    private String password;

   //以下省略了所有成员变量的get和set方法......
   
}

创建文件"UserMapper.xml"映射文件作为ORM中的“M”





<mapper namespace="com.young.mapper.UserMapper">
    
    
    <select id="selectAll" resultType="com.young.model.User">
        select * from user
    select>
mapper>

测试类:

import com.alibaba.fastjson.JSON;
import com.young.model.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class TestMapper {
    @Test
    public void testMapper() throws IOException {
        //获取字节输入流,用于读取配置文件
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        //通过session工厂构建器构建session工厂
        //SqlSessionFactory可以获取SqlSession对象,只能是唯一存在的
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //SqlSession可以类比为javaWeb中的session,表示程序和数据库的一次交互
        //可以与数据库建立连接并执行查询、更新等语句
        //此对象需要每次操作都是一个新的对象,不能放在全局供多个线程共同使用
        SqlSession session = sessionFactory.openSession();
        //执行Sql语句,传递Sql的唯一标识,即namespace.Sqlid
        //selectList将查询的结果封装为一个List
        //mybatis会将数据库中查询出的列和java实体类的属性一一对应,否则该属性不被赋值,如果名称不一致,可以在配置文件中配置或者使用别名
        List<User> list = session.selectList("com.young.mapper.UserMapper.selectAll");
        System.out.println(JSON.toJSONString(list,true));
    }
}
每个基于MyBatis的应用都是以一个SqlSessionFactory的实例为核心的,SqlSessionFactoryBuilder可以从XML配置文件或一个预先配置的
Configuration实例来构建出SqlSessionFactory实例。MyBatis提供了一个Resources工具类,使得从类路径或其它位置加载资源文件更加容易。

SqlSessionFactoryBuilder
这个类可以被实例化、使用和丢弃,一旦创建了SqlSessionFactory,就不再需要它了。 因此SqlSessionFactoryBuilder实例的最佳作用域
是方法作用域(也就是局部方法变量)。在程序中最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。 
SqlSessionFactory
SqlSessionFactory一旦被创建就应该在应用的运行期间一直存在,不能丢弃它或重新创建另一个实例。 使用SqlSessionFactory的最佳实践是
在应用运行期间不要重复创建多次。因此SqlSessionFactory的最佳作用域是应用作用域。 可以使用单例模式来做到这一点。
SqlSession
每个线程都应该有它自己的SqlSession实例。SqlSession的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。也绝不能将 SqlSession 实例的引用放在任何类型的托
管作用域中,比如Servlet框架中的HttpSession。如果你现在正在使用一种Web框架,考虑将SqlSession放在一个和HTTP请求相似的作用域中。
换句话说,每次收到HTTP请求,就可以打开一个SqlSession,返回一个响应后,就关闭它。这个关闭操作很重要,为了确保每次都能执行关闭操作,
你应该把这个关闭操作放到 finally 块中。

maven默认不会将src/main/java中的xml文件编译,在pom.xml中增加配置

<build>
    <resources>
        <resource>
            <directory>src/main/javadirectory>
            <includes>
                <include>**/*.xmlinclude>
            includes>
        resource>
    resources>
build>

优化配置

读取配置文件获取数据库连接的参数

在配置文件"mybatis-config.xml"中,数据库连接的参数可以从properties文件中获取
db.properties配置文件

db.url=jdbc:mysql://localhost:3306/mybatis_db?serverTimezone=UTC
db.username=root
db.password=123
db.driverClassName=com.mysql.jdbc.Driver

在mybatis-config.xml文件中增加如下配置来读取配置文件



<properties resource="db.properties"/>

mybatis-config.xml文件中修改数据库连接的参数

<dataSource type="POOLED">
    
    <property name="driver" value="${db.driverClassName}"/>
    <property name="url" value="${db.url}"/>
    <property name="username" value="${db.username}"/>
    <property name="password" value="${db.password}"/>
dataSource>
日志配置

MyBatis框架在执行时是黑箱操作,MyBatis框架记录了日志,只需要增加jar包,编写配置文件就可以展示执行过程中的信息。
导入jar包

 
<dependency>
	<groupId>log4jgroupId>
	<artifactId>log4jartifactId>
	<version>1.2.17version>
dependency>

配置文件log4j.properties

#USE THIS SETTING FOR OUTPUT MYBATIS`s SQL ON THE CONSOLE
log4j.rootLogger=debug, Console,E

#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
#log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.appender.Console.layout.ConversionPattern=[ %l ] %d{yyyy/MM/dd HH:mm:ss} %-5p [%c{1}] - %l - %m%n

### \u4FDD\u5B58\u5F02\u5E38\u4FE1\u606F\u5230\u5355\u72EC\u6587\u4EF6 ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File = error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

再运行程序就会输出日志,比如执行的Sql语句,参数以及查询的数据条数

[ org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159) ] 2020/05/22 16:23:29 DEBUG [selectAll] - org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159) - ==>  Preparing: select * from user 
[ org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159) ] 2020/05/22 16:23:29 DEBUG [selectAll] - org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159) - ==> Parameters: 
[ org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159) ] 2020/05/22 16:23:29 DEBUG [selectAll] - org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159) - <==      Total: 2

Mapper映射文件

在UserMapper.xml文件中配置增删改查的Sql语句




        
<mapper namespace="com.young.mapper.UserMapper">
    
    <select id="selectAll" resultType="com.young.model.User">
        select * from user
    select>
    
    <select id="selectById" resultType="com.young.model.User">
        select * from user where id=#{id}
    select>
    
    <update id="update" parameterType="com.young.model.User">
        update user set username=#{username} where id=#{id}
    update>
    
    <insert id="insert" parameterType="com.young.model.User">
        insert into user values(#{id},#{username},#{password})
    insert>
    
    <delete id="delete">
        delete from user where id=#{id}
    delete>
mapper>

测试类
测试根据id查询单条数据
在其他测试代码中省略获取SqlSession实例的过程

@Test
public void testMapper() throws IOException {
    InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
    SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession session = sessionFactory.openSession();
  	User user = session.selectOne("com.young.mapper.UserMapper.selectById",1);
    System.out.println(JSON.toJSONString(user));
}

测试更新数据

User user = new User();
user.setId(1);
user.setUsername("abc");
//返回影响的行数
session.update("com.young.mapper.UserMapper.update", user);
//MyBatis默认为手动提交,所以对于增删改操作需要调用commit()方法
session.commit();

测试插入数据

User user = new User();
user.setId(5);
user.setPassword("555");
user.setUsername("eee");
//返回影响的行数
session.insert("com.young.mapper.UserMapper.insert", user);
session.commit();

插入数据时的日志记录
根据日志可以看出,他会根据根据参数的类型和名称实现注入

[ org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159) ] 2020/05/22 16:31:49 DEBUG [insert] - org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159) - ==>  Preparing: insert into user values(?,?,?) 
[ org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159) ] 2020/05/22 16:31:49 DEBUG [insert] - org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159) - ==> Parameters: 5(Integer), eee(String), 555(String)
[ org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159) ] 2020/05/22 16:31:49 DEBUG [insert] - org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:159) - <==    Updates: 1
[ org.apache.ibatis.transaction.jdbc.JdbcTransaction.commit(JdbcTransaction.java:70) ] 2020/05/22 16:31:49 DEBUG [JdbcTransaction] - org.apache.ibatis.transaction.jdbc.JdbcTransaction.commit(JdbcTransaction.java:70) - Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@467aecef]

测试删除数据

//返回影响的行数
session.delete("com.young.mapper.UserMapper.delete", 5);
session.commit();
resultType:表示执行Sql语句返回结果的类型
	selectList()方法会返回一个List集合,MyBatis会将查询出的每一条数据封装为User对象并存入List集合。
	selectOne()方法会返回一个resultType属性指定类的对象,MyBatis会将查询出单条数据封装为User对象。
	如果查询出多条数据却使用了selectOne()方法,会出现异常。
	如果返回结果为自定义类型,结果的列明需要和自定义类的setXxx()方法中"Xxx"名称保持一致。如setUsername(),那么列明就为"username"
parameterType:表示输入参数的类型
	使用#{}作为参数的占位符
	如果数据类型为基本数据类型(包括包装类)以及String,可以不用设置输入参数类型,MyBatis会实现自动注入
	如果指定输入参数的类型为自定义类,如User类,那么User类中的属性名需要和#{}中的参数名一致
	
	区分${}和#{}
	${}在mybatis-config.xml中可以读取配置文件中的内容,也可以用在mapper.xml中,但是慎用!
	${}值只可以为value,且只会将值直接拼接在sql语句中,无任何处理,如下所示:
	
    在运行时,Sql语句为:"select * from user where username=aaa";当值为String类型时,不会给值拼接引号。
    而#{}中的值为列名,比如${id}、${username},且将值拼接在sql语句中时会拼接引号
    在运行时,Sql语句为:"select * from user where username='aaa'";
    所以如果要使用${},需要在传递参数时加上引号,而且使用${}时如果没有拦截器存在发生Sql注入的风险。	

在UserMapper.xml文件中,对于resultType以及parameterType每次都要写完整的包名及类名,可以使用别名来简化书写
在mybatis-config.xml文件中增加如下配置

<typeAliases>
	
	<typeAlias type="com.young.model.User" alias="User"/>
    
    
    
typeAliases>
标签进行别名设置时,在在UserMapper.xml文件中Sql语句标签如下:
标签进行别名设置时,在在UserMapper.xml文件中Sql语句标签如下:

resultType的值可以为"user",也可以为"User"。

需要注意节点中的内容顺序,否则会报错。顺序如下:
properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?"。

你可能感兴趣的:(mybatis,java)