MyBatis基础

MyBatis基本使用

日志框架

1、日志框架
	在项目开发过程中,我们可以通过 debug 查找问题。而在线上环境我们查找问题只能通过打印日志的方式查找问题。因此对于一个项目而言,日志记录是一个非常重要的问题。因此,如何选择一个合适的日志记录框架也非常重要。
	在Java开发中,目前常用的日志框架包括Log4j 1,Log4j 2,Commons Logging,Slf4j,Logback,Jul。这些日志记录框架各有各的特点,各有各的应用场景。了解这些框架的特点及应用场景,有利于我们做技术选型的时候做出正确的判断。
框架说明
Log4jApache Log4j是一个基于Java的日志记录工具。它是由Ceki首创的,现在则是Apache软件基金会的一个项目。 Log4j是几种Java日志框架之一。
Log4j 2Apache Log4j 2是apache开发的一款Log4j的升级产品。
Commons LoggingApache基金会所属的项目,是一套Java日志接口,之前叫Jakarta Commons Logging,后更名为Commons Logging。
Slf4j类似于Commons Logging,是一套简易Java日志门面,本身并无日志的实现。(Simple Logging Facade for Java,缩写Slf4j)。
Logback一套日志组件的实现(Slf4j阵营)
Jul(Java Util Logging),自Java1.4以来的官方日志实现。
Java日志框架历史:
	1996年早期,欧洲安全电子市场项目组决定编写它自己的程序跟踪API(Tracing API)。经过不断的完善,这个API终于成为一个十分受欢迎的Java日志软件包,即Log4j(由Ceki创建)。后来Log4j成为Apache基金会项目中的一员,Ceki也加入Apache组织。
	后来Log4j近乎成了Java社区的日志标准。据说Apache基金会还曾经建议Sun引入Log4j到Java的标准库中,但Sun拒绝了。
	2002年Java1.4发布,Sun推出了自己的日志库JUL(Java Util Logging),其实现基本模仿了Log4j的实现。在JUL出来以前,Log4j就已经成为一项成熟的技术,使得Log4j在选择上占据了一定的优势。
	接着,Apache推出了Jakarta Commons Logging,JCL只是定义了一套日志接口(其内部也提供一个Simple Log的简单实现),支持运行时动态加载日志组件的实现,也就是说,在你应用代码里,只需调用Commons Logging的接口,底层实现可以是Log4j,也可以是Java Util Logging。
	后来(2006年),Ceki不适应Apache的工作方式,离开了Apache。然后先后创建了Slf4j(日志门面接口,类似于Commons Logging)和Logback(Slf4j的实现)两个项目,并回瑞典创建了QOS公司,QOS官网上是这样描述Logback的:The Generic,Reliable Fast&Flexible Logging Framework(一个通用,可靠,快速且灵活的日志框架)。
	
	现今,Java日志领域被划分为两大阵营:Commons Logging阵营和Slf4j阵营。
Commons Logging在Apache大树的笼罩下,有很大的用户基数。但有证据表明,形式正在发生变化。2013年底有人分析了GitHub上30000个项目,统计出了最流行的100个Libraries,可以看出Slf4j的发展趋势更好。
	Apache眼看有被Logback反超的势头,于2012-07重写了Log4j 1.x,成立了新的项目Log4j 2, Log4j 2具有Logback的所有特性。
2、日志框架关系
1 Log4j 2与Log4j 1发生了很大的变化,Log4j 2不兼容Log4j 1。
2 Commons Logging和Slf4j是日志门面(门面模式是软件工程中常用的一种软件设计模式,也被称为正面模式、外观模式。它为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易使用)。Log4j和Logback则是具体的日志实现方案。可以简单的理解为接口与接口的实现,调用者只需要关注接口而无需关注具体的实现,做到解耦。
3 比较常用的组合使用方式是Slf4j与Logback组合使用,Commons Logging与Log4j组合使用。
4 Logback必须配合Slf4j使用。由于Logback和Slf4j是同一个作者,其兼容性不言而喻。

未来使用Slf4j与Logback组合会越来越多
(1)Slf4j实现机制决定Slf4j限制较少,使用范围更广
 (2)Logback拥有更好的性能。
 (3)Logback文档免费。
3 log4j的使用

共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF。

log4j 1.2.x版本的使用

依赖信息

<!--门面commons-logging-->
<dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
</dependency> 

<dependency>
           <groupId>log4j</groupId>
           <artifactId>log4j</artifactId>
           <version>1.2.17</version>
 </dependency>

第一步:配置文件:log4j.properties

### set log levels - for more verbose logging change 'info' to 'debug' , 'off' ###
log4j.rootLogger=info, stdout,file

###1 direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

###2 direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=d:\\mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n


###3每天生成一个文件
log4j.appender.daily=org.apache.log4j.DailyRollingFileAppender
log4j.appender.daily.File=d:\\logs\\soso.log
log4j.appender.daily.Append=true
log4j.appender.daily.Threshold=INFO
log4j.appender.daily.ImmediateFlush=true
#生成一个配置文件 命名  soso.8888-88-88-88 时间
log4j.appender.daily.DatePattern='_'yyyy-MM-dd'.txt'
log4j.appender.daily.layout=org.apache.log4j.PatternLayout
log4j.appender.daily.layout.ConversionPattern=[%-5p] %d(%r) --> [%t] %l: %m %x %n

###4控制每个滚动日志文件大小和个数
log4j.appender.R=org.apache.log4j.RollingFileAppender  
log4j.appender.R.Threshold=DEBUG  
log4j.appender.R.File=d:\\logs\\test.log  
log4j.appender.R.layout=org.apache.log4j.PatternLayout  
log4j.appender.R.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%5p] - %c -%F(%L) -%m%n
log4j.appender.R.MaxFileSize=1kb
log4j.appender.R.MaxBackupIndex=5

第二步 编写java类测试:

import org.apache.log4j.Logger;

public class Demo1 {
	public static void main(String[] args) {
		//不用日志框架
		System.out.println("xxxx");
	
         Logger logger = LogManager.getLogger(LogDemo2.class.getName());
      	//门面使用
      	 //Log logger = LogFactory.getLog(Demo2.class.getName());
		//使用日志
		logger.trace("跟踪信息");
		logger.debug("调试信息");
		logger.info("信息");
		logger.warn("警告信息");
		logger.error("错误信息");
		logger.fatal("致命错误");
	}
}
4 log4j 2.x的使用

依赖信息

<!--门面commons-logging-->
<dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
</dependency> 
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.11.1</version>
</dependency>

如果和commons-logging配合使用需要添加log4j-jcl依赖

<dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-jcl</artifactId>
            <version>2.11.1</version>
</dependency>

第一步:配置文件:log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Appenders>
        <Console name="STDOUT" target="SYSTEM_OUT">
            <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="warn">
            <AppenderRef ref="STDOUT"/>
        </Root>
    </Loggers>
</Configuration>

第二步 编写java类测试:


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
 * @author wgy 2018/12/10 21:52
 * @version 1.0
 */
public class LogDemo2 {
    public static void main(String[] args){
        Logger logger = LogManager.getLogger(LogDemo2.class.getName());
       
        //门面使用
      	//Log logger = LogFactory.getLog(Demo2.class.getName());
      
        logger.trace("entry");	//等同于logger.entry();但此方法在新版本好像已经废弃

        logger.error("Did it again!");

        logger.info("这是info级信息");

        logger.debug("这是debug级信息");

        logger.warn("这是warn级信息");

        logger.fatal("严重错误");

        logger.trace("exit");
    }
}
5 logback的使用

logback是java的日志开源组件,是log4j创始人写的,性能比log4j要好,目前主要分为3个模块

  1. logback-core:核心代码模块
  2. logback-classic:log4j的一个改良版本,同时实现了slf4j的接口,这样你如果之后要切换其他日志组件也是一件很容易的事
  3. logback-access:访问模块与Servlet容器集成提供通过Http来访问日志的功能

依赖如下

<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.2.3</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.26</version>
</dependency>

logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration >
    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
    <property name="LOG_HOME" value="D:/" /><!-- 日志文件的家目录 -->
    <timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss" /><!-- 生成指定格式的时间戳,用于日志文件的唯一命名 -->
    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>

    <appender name="fileAppender" class="ch.qos.logback.core.FileAppender">
        <immediateFlush>true</immediateFlush><!-- 立即刷新输出流,设置为 false 可以提高日志吞吐量 -->
        <file>${LOG_HOME}${bySecond}.log</file><!-- 日志文件路径 -->
        <encoder><!-- 日志输出格式,必须指定,否则不会往文件输出内容 -->
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} - %msg%n</pattern>
        </encoder>
        <append>true</append><!-- 追加 -->
        <prudent>false</prudent><!-- 关闭严格模式,也提高日志吞吐量(3倍),默认false -->
    </appender>

    <!-- 日志输出级别 -->
    <root level="DEBUG">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

代码如下

Logger logger = LoggerFactory.getLogger(Demo3.class.getName());
logger.trace("跟踪信息_logback");
logger.debug("调试信息_logback");
logger.info("基本信息_logback");
logger.warn("警告信息_logback");
logger.error("错误信息_logback");

MyBatis

mybaits的代码由github.com管理,下载地址:https://github.com/mybatis/mybatis-3/releases

依赖信息

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.6</version>
</dependency>

学习地址:http://www.mybatis.org/mybatis-3/zh/index.html

使用版本:3.4.6

概述

MyBatis主要就完成2件事情

  1. 封装JDBC操作
  2. 利用反射打通Java类与SQL语句之间的相互转换

MyBatis的主要设计目的就是让我们对执行SQL语句时对输入输出的数据管理更加方便,所以方便地写出SQL和方便地获取SQL的执行结果才是MyBatis的核心竞争力。

特点
  • 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
  • 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql基本上可以实现我们不使用数据访问框架可以实现的所有功能,或许更多。
  • 解除sql与程序代码的耦合:通过提供DAL层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
  • 提供映射标签,支持对象与数据库的orm字段关系映射
  • 提供对象关系映射标签,支持对象关系组建维护
  • 提供xml标签,支持编写动态sql
体系结构

mybatis配置文件,包括Mybatis全局配置文件和Mybatis映射文件,其中全局配置文件配置了数据源、事务等信息;映射文件配置了SQL执行相关的信息。

  • mybatis通过读取配置文件信息(全局配置文件和映射文件),构造出SqlSessionFactory,即会话工厂。
  • 通过SqlSessionFactory,可以创建SqlSession即会话。Mybatis是通过SqlSession来操作数据库的。
  • SqlSession本身不能直接操作数据库,它是通过底层的Executor执行器接口来操作数据库的。Executor接口有两个实现类,一个是普通执行器,一个是缓存执行器(默认)。
  • Executor执行器要处理的SQL信息是封装到一个底层对象MappedStatement中。该对象包括:SQL语句、输入参数映射信息、输出结果集映射信息。其中输入参数和输出结果的映射类型包括java的简单类型、HashMap集合对象、POJO对象类型。
加入配置文件

在resources目录中添加Mybatis的核心配置mybatis-config.xml、log4j日志文件log4j.properties

<?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>
	<!-- 和spring整合后 environments配置将废除 -->
	<environments default="development">
		<environment id="development">
			<!-- 使用jdbc事务管理 -->
			<transactionManager type="JDBC" />
			<!-- 数据库连接池 -->
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver" />
				<property name="url"
					value="jdbc:mysql://localhost:3306/mybatis_01?characterEncoding=utf-8" />
				<property name="username" value="root" />
				<property name="password" value="root" />
			</dataSource>
		</environment>
	</environments>
</configuration>
### set log levels - for more verbose logging change 'info' to 'debug' , 'off' ###
log4j.rootLogger=info, stdout,file

### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=d:\\mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
:创建POJO

domain

bean

entity

pojo

在不同的场合使用的对象的分类:

po : Persistent Object (持久化对象)

vo:View Object (视图对象 ,PageBean)

dto: Data Transfer Object (数据传输对象 ,系统与系统之间传递数据)

bo : Business Object (业务对象)

什么是POJO:

POJO是Plain Old Java Objects的缩写,POJO实质上可以理解为简单的实体类,顾名思义POJO类的作用是方便程序员使用数据库中的数据表,对于广大的程序员,可以很方便的将POJO类当做对象来进行使用,当然也是可以方便的调用其get,set方法。

User.java

public class User {
	private int id;
	private String username;// 用户姓名
	private String sex;// 性别
	private Date birthday;// 生日
	private String address;// 地址
	//getter和setter
}
加入sql映射文件

在resources目录下创建com.mapper文件夹(注意要一个一个的创建),然后创建UserMapper.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:命名空间,用于隔离sql,还有一个很重要的作用,后面会讲 -->
<mapper namespace="test">
  
</mapper>
加载映射文件
MyBatis框架需要加载UserMapper.xml映射文件,将UserMapper.xml添加在mybatis-config.xml,如下:

<mappers>
        <mapper resource="com/mapper/UserMapper.xml"/>
</mappers>
实现根据id查询用户

(1)使用SQL语句:SELECT * FROM user WHERE id = 1

(2)映射文件中添加:

<?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:命名空间,用于隔离sql,还有一个很重要的作用,后面会讲 -->
<mapper namespace="test">
  	<!-- id:statement的id 或者叫做sql的id-->
	<!-- parameterType:声明输入参数的类型 -->
	<!-- resultType:声明输出结果的类型,应该填写pojo的全路径 -->
	<!-- #{}:输入参数的占位符,相当于jdbc的?
	        如果是简单类型(基本类型、字符串类型)名称可以任意-->
	<select id="queryUserById" parameterType="Integer"
            resultType="com.pojo.User">
		SELECT * FROM `user` WHERE id  = #{id}
	</select>
</mapper

(3)测试程序:

1. 创建SqlSessionFactoryBuilder对象
2. 加载SqlMapConfig.xml配置文件
3. 创建SqlSessionFactory对象
4. 创建SqlSession对象
5. 执行SqlSession对象执行查询,获取结果User
6. 打印结果
7. 释放资源

MyBatis框架中涉及到的几个API:

  • SqlSessionFactoryBuilder:该对象负责根据MyBatis配置文件SqlMapConfig.xml构建SqlSessionFactory实例
  • SqlSessionFactory:每一个MyBatis的应用程序都以一个SqlSessionFactory对象为核心。该对象负责创建SqlSession对象实例。
  • SqlSession:该对象包含了所有执行SQL操作的方法,用于执行已映射的SQL语句

代码如下

	@Test
    public void test1(){
        try {
            // 1. 创建SqlSessionFactoryBuilder对象
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            // 2. 加载SqlMapConfig.xml配置文件
            InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
            // 3. 创建SqlSessionFactory对象
            SqlSessionFactory factory = sqlSessionFactoryBuilder.build(inputStream);
            //4.创建SqlSession
            SqlSession sqlSession = factory.openSession();
            //5执行
            User user = sqlSession.selectOne("test.queryUserById", 1);
            // 6. 打印结果
            System.out.println(user);
            // 7. 释放资源
            sqlSession.close();

        } catch (IOException e) {
            e.printStackTrace();
        }

    }
根据用户名模糊查询用户

使用SQL语句:

SELECT * FROM `user` WHERE username LIKE '%王%'

映射文件中添加

方式1

<select id="queryUserByUsername1" parameterType="String"
		resultType="com.pojo.User">
		SELECT * FROM `user` WHERE username LIKE #{username}
</select>

测试代码

	@Test
	public void test2() throws Exception {
        // 1. 创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        // 2. 加载SqlMapConfig.xml配置文件
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        // 3. 创建SqlSessionFactory对象
        SqlSessionFactory factory = sqlSessionFactoryBuilder.build(inputStream);
		// 4. 创建SqlSession对象
		SqlSession sqlSession = sqlSessionFactory.openSession();
		// 5. 执行SqlSession对象执行查询,获取结果User
		// 查询多条数据使用selectList方法
		List<Object> list = sqlSession.selectList("queryUserByUsername1", "%王%");
		// 6. 打印结果
		for (Object user : list) {
			System.out.println(user);
		}
		// 7. 释放资源
		sqlSession.close();
	}

方式2:

<!-- 如果传入的参数是简单数据类型,${}里面必须写value -->
	<select id="queryUserByUsername2" parameterType="string"
		resultType="com.pojo.User">
		SELECT * FROM `user` WHERE username LIKE '%${value}%'
	</select>

测试代码:

	//省略
	// 4. 创建SqlSession对象
	SqlSession sqlSession = sqlSessionFactory.openSession();

	// 5. 执行SqlSession对象执行查询,获取结果User
	// 查询多条数据使用selectList方法
	List<Object> list = sqlSession.selectList("queryUserByUsername2", "王");

	// 6. 打印结果
	for (Object user : list) {
		System.out.println(user);
	}

	// 7. 释放资源
	sqlSession.close();

#{}和${}的区别

(1)#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换。#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它任意名称。

(2)${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。

parameterType和resultType

parameterType:指定输入参数类型,MyBatis通过ognl从输入对象中获取参数值拼接在sql中。

resultType:指定输出结果类型,MyBatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。如果有多条数据,则分别进行映射,并把对象放到容器List中
实现新增用户

使用的SQL语句

INSERT INTO `user` (username,birthday,sex,address) VALUES 
('黄晓明','2010-05-20','1','南京')

映射文件配置标签,用于执行插入操作。

<!-- 保存用户 -->
<insert id="add" parameterType="com.pojo.User">
		INSERT INTO `user`
		(username,birthday,sex,address) VALUES
		(#{username},#{birthday},#{sex},#{address})
</insert>

测试代码

@Test
public void test4() {
	// 4. 创建SqlSession对象
	SqlSession sqlSession = sqlSessionFactory.openSession();

	// 5. 执行SqlSession对象执行保存
	// 创建需要保存的User
	User user = new User();
	user.setUsername("黄晓明");
	user.setSex("1");
	user.setBirthday(new Date());
	user.setAddress("南京");

	sqlSession.insert("test.add", user);
	System.out.println(user);

	// 需要进行事务提交
	sqlSession.commit();

	// 7. 释放资源
	sqlSession.close();
}

​ 在插入操作完成之前或之后,可以配置标签获得生成的主键的值,获得插入之前还是之后的值,可以通过配置order属性来指定。

​ LAST_INSERT_ID:该函数是mysql的函数,获取自增主键的ID,它必须配合insert语句一起使用

<!-- 添加用户 -->
     <!-- selectKey:查询主键,在标签内需要输入查询主键的sql -->
     <!-- order:指定查询主键的sql和insert语句的执行顺序,相当于insert语句来说 -->
     <!-- LAST_INSERT_ID:该函数是mysql的函数,获取自增主键的ID,它必须配合insert语句一起使用 -->
     
<insert id="addUser" parameterType="com.qf.po.User”>

     <!-- selectKey 标签实现主键返回 -->
	<!-- keyProperty:主键对应的pojo中的哪一个属性 -->
	<!-- order:设置在执行insert语句前执行查询id的sql,还是在执行insert语句之后执行查询id的sql -->
	<!-- resultType:设置返回的id的类型 -->
<selectKey keyProperty="id" resultType="int" order="AFTER">
	SELECT LAST_INSERT_ID() 
</selectKey>

INSERT INTO USER(username,birthday,sex,address)
        VALUES(#{username},#{birthday},#{sex},#{address})
</insert>	

​ 测试代码如下,直接执行配置的statement,可以查看结果。

SqlSession session = sqlSessionFactory.openSession();
session.insert("test.add",user);
session.commit();
实现删除操作

使用SQL语句

DELETE FROM `user` WHERE id = 47

在映射文件文件中使用标签配置删除的statement。

<delete id="deleteUser" parameterType="int">
	  	delete from user where id=#{id}
</delete>

测试代码如下,直接执行配置的statement,可以查看结果。

SqlSession session = sqlSessionFactory.openSession();
session.delete("test.deleteUser",1);
session.commit();
实现修改操作

使用SQL语句

UPDATE `user` SET username = '马云' WHERE id = 26

在映射文件使用标签配置修改的statement。

<update id="updateUser" parameterType="com.qf.pojo.User">
	  	update user set username=#{username},sex=#{sex},birthday=#{birthday},address=#{address}  where id= #{id}
</update>

​ 测试代码如下,直接执行配置的statement,可以查看结果。

 //构建user参数,没有赋值的属性采取默认值
    User user = new User();
    user.setId(20);
    user.setUsername("admin");
    user.setAddress("beijing");
      
    // 第一个参数:statement的id,建议:namespace.statementId(确保唯一)
    // 第二个参数:入参的值,它的类型要和映射文件中对应的statement的入参类型一致
    sqlSession.update("test.updateUser", user);

MyBatis两种开发方式

一、

使用MyBatis开发Dao,通常有两种方式,即原始Dao开发方式和Mapper接口动态代理开发方式。推荐使用第二种。

MyBatis核心API说明:

(1)SqlSession的使用范围

SqlSession中封装了对数据库的操作,如:查询、插入、更新、删除等。
SqlSession通过SqlSessionFactory创建。
SqlSessionFactory是通过SqlSessionFactoryBuilder进行创建。

(2)SqlSessionFactoryBuilder

SqlSessionFactoryBuilder用于创建SqlSessionFactory,SqlSessionFactory一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory创建的。所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。

(3)SqlSessionFactory

 SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory

(4)SqlSession

  SqlSession是一个面向用户的接口,sqlSession中定义了数据库操作方法。
  每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。
    打开一个 SqlSession;使用完毕就要关闭它。通常把这个关闭操作放到 finally 块中以确保每次都能执行关闭。如下:
SqlSession session = sqlSessionFactory.openSession();

try {

     // do work

} finally {
    session.close();

}
MyBatis工具类的封装

为了方便使用SqlSession对象,需要封装工具类MyBatisUtils.java

package com.utils;

import java.io.IOException;
import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class MyBatisUtils {
	public  static SqlSessionFactory factory;
	static{
		try {
			//0获取流
			InputStream is=Resources.getResourceAsStream("SqlMapConfig.xml");
			//1FactoryBuilder
			factory=new SqlSessionFactoryBuilder().build(is);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	public static SqlSession openSession(){
		return factory.openSession();
	}
}	
原始Dao方式

原始Dao开发方法需要程序员编写Dao接口和Dao实现类。

实现功能:

使用MyBatis开发DAO实现以下的功能:
(1)根据用户id查询一个用户信息
(2)根据用户名称模糊查询用户信息列表
(3)添加用户信息
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">
<!-- namespace:命名空间,用于隔离sql,还有一个很重要的作用,后面会讲 -->
<mapper namespace="test">

	<!-- 根据id查询用户 -->
	<select id="queryUserById" parameterType="int"
		resultType="cn.MyBatis.pojo.User">
		select * from user where id = #{id}
	</select>

	<!-- 根据username模糊查询用户 -->
	<select id="queryUserByUsername" parameterType="string"
		resultType="cn.MyBatis.pojo.User">
		select * from user where username like '%${value}%'
	</select>

	<!-- 保存用户 -->
	<insert id="saveUser" parameterType="cn.MyBatis.pojo.User">
		<selectKey keyProperty="id" keyColumn="id" order="AFTER"
			resultType="int">
			SELECT LAST_INSERT_ID()
		</selectKey>
		insert into user(username,birthday,sex,address)
		values(#{username},#{birthday},#{sex},#{address})
	</insert>

</mapper>

2:创建DAO接口
public interface UserDao {
	/**
	 * 根据id查询用户
	 * 
	 * @param id
	 * @return
	 */
	User queryUserById(int id);

	/**
	 * 根据用户名模糊查询用户
	 * 
	 * @param username
	 * @return
	 */
	List<User> queryUserByUsername(String username);

	/**
	 * 保存用户
	 * 
	 * @param user
	 */
	void saveUser(User user);
}
3:Dao实现类
public class UserDaoImpl implements UserDao {
	

	@Override
	public User queryUserById(int id) {
		// 创建SqlSession
		SqlSession sqlSession = MyBatisUtils.openSession();
		// 执行查询逻辑
		User user = sqlSession.selectOne("queryUserById", id);
		// 释放资源
		sqlSession.close();

		return user;
	}

	@Override
	public List<User> queryUserByUsername(String username) {
		// 创建SqlSession
		SqlSession sqlSession = MyBatisUtils.openSession();

		// 执行查询逻辑
		List<User> list = sqlSession.selectList("queryUserByUsername", username);
		// 释放资源
		sqlSession.close();
		return list;
	}

	@Override
	public void saveUser(User user) {
		// 创建SqlSession
		SqlSession sqlSession = MyBatisUtils.openSession();

		// 执行保存逻辑
		sqlSession.insert("saveUser", user);
		// 提交事务
		sqlSession.commit();
		// 释放资源
		sqlSession.close();
	}
}
4:测试

代码略

二、

Mapper接口动态代理方式

开发规范:

Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由MyBatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。

Mapper接口开发需要遵循以下规范:
1、Mapper.xml文件中的namespace与mapper接口的类路径相同。
2、Mapper接口方法名和Mapper.xml中定义的每个statement的id相同 
3、Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同(注意:mapper.xml中parameterType可不写,如果不写则由Mapper接口中的方法参数类型决定)
4、Mapper接口方法的返回值类型和mapper.xml中定义的每个sql的resultType(输出参数类型)的类型相同
1:编写映射文件

在com.qf.mapper包中添加UserMapper.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:命名空间,用于隔离sql -->
<!-- 还有一个很重要的作用,使用动态代理开发DAO,1. namespace必须和Mapper接口类路径一致 -->
<mapper namespace="com.mapper.UserMapper">
	<!-- 根据用户id查询用户 -->
	<!-- 2. id必须和Mapper接口方法名一致 -->
	<!-- 3. parameterType必须和接口方法参数类型一致 -->
	<!-- 4. resultType必须和接口方法返回值类型一致 -->
	<select id="queryUserById" parameterType="int"
		resultType="cn.MyBatis.pojo.User">
		select * from user where id = #{id}
	</select>

	<!-- 根据用户名查询用户 -->
	<select id="queryUserByUsername" parameterType="string"
		resultType="com.MyBatis.pojo.User">
		select * fromuser where username like '%${value}%'
	</select>

	<!-- 保存用户 -->
	<insert id="saveUser" parameterType="com.pojo.User">
		<selectKey keyProperty="id" keyColumn="id" order="AFTER"
			resultType="int">
			select last_insert_id()
		</selectKey>
		insert into user(username,birthday,sex,address) values
		(#{username},#{birthday},#{sex},#{address});
	</insert>

</mapper>
2: 创建DAO接口

在com.qf.mapper包中添加UserMapper.java接口

public interface UserMapper {
	/**
	 * 根据id查询
	 * 
	 * @param id
	 * @return
	 */
	User queryUserById(int id);

	/**
	 * 根据用户名查询用户
	 * 
	 * @param username
	 * @return
	 */
	List<User> queryUserByUsername(String username);

	/**
	 * 保存用户
	 * 
	 * @param user
	 */
	void saveUser(User user);
}
3: 加载映射文件
<mappers>
     <mapper resource=*"com.qf.mapper/UserMapper.xml"* />
 </mappers>
4:测试
@Test
	public void testQueryUserById() {
		// 获取sqlSession
		SqlSession sqlSession = MyBatisUtils.openSession();

		// 从sqlSession中获取Mapper接口的代理对象
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		// 执行查询方法
		User user = userMapper.queryUserById(1);
		System.out.println(user);

		// 和spring整合后由spring管理
		sqlSession.close();
	}

	@Test
	public void testQueryUserByUsername() {
		// 获取sqlSession
		SqlSession sqlSession = MyBatisUtils.openSession();

		// 从sqlSession中获取Mapper接口的代理对象
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		// 执行查询方法
		List<User> list = userMapper.queryUserByUsername("张");
		for (User user : list) {
			System.out.println(user);
		}

		// 和spring整合后由spring管理
		sqlSession.close();
	}

	@Test
	public void testSaveUser() {
		// 获取sqlSession
		SqlSession sqlSession = MyBatisUtils.openSession();

		// 从sqlSession中获取Mapper接口的代理对象
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		// 创建保存对象
		User user = new User();
		user.setUsername("李小璐");
		user.setBirthday(new Date());
		user.setSex("1");
		user.setAddress("上海");
		// 执行查询方法
		userMapper.saveUser(user);
		System.out.println(user);


		// 和spring整合后由spring管理
		sqlSession.commit();
		sqlSession.close();
	}

总结:

selectOne和selectList
	动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。
namespace
	MyBatis官方推荐使用mapper代理方法开发mapper接口,程序员不用编写mapper接口实现类,使用mapper代理方法时,输入参数可以使用pojo包装对象或map对象,保证dao的通用性。

MyBatis核心配置文件

MyBatis的核心配置mybatis-config.xml中包含内容顺序如下:

    properties(属性)
    settings(全局配置参数)
    typeAliases(类型别名)
    typeHandlers(类型处理器)
    objectFactory(对象工厂)
    plugins(插件)
    environments(环境集合属性对象)
    environment(环境子属性对象)
    transactionManager(事务管理)
    dataSource(数据源)
    mappers(映射器)
1 properties(属性)

自定义db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/MyBatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root

mybatis-config.xml文件中引用

<?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>
	<!-- 是用resource属性加载外部配置文件 -->
	<properties resource="db.properties">
		<!-- 在properties内部用property定义属性 -->
		<!-- 如果外部配置文件有该属性,则内部定义属性被外部属性覆盖 -->
		<property name="jdbc.username" value="root" />
		<property name="jdbc.password" value="root" />
	</properties>

	<!-- 和spring整合后 environments配置将废除 -->
	<environments default="development">
		<environment id="development">
			<!-- 使用jdbc事务管理 -->
			<transactionManager type="JDBC" />
			<!-- 数据库连接池 -->
			<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>
	</environments>
MyBatis 将按照下面的顺序来加载属性:
(1)在 properties 元素体内定义的属性首先被读取。 
(2)然后会读取properties 元素中resource或 url 加载的属性,它会覆盖已读取的同名属性
2 typeAliases(类型别名)

MyBatis支持的别名

别名	    映射的类型
_byte 	    byte 
_long 	    long 
_short 	    short 
_int 	    int 
_integer    int 
_double     double 
_float 	    float 
_boolean     boolean 
string 	     String 
byte 	    Byte 
long 	    Long 
short 	    Short 
int 	    Integer 
integer      Integer 
double 	     Double 
float 	     Float 
boolean      Boolean 
date 	     Date 
decimal      BigDecimal 
bigdecimal 	 BigDecimal 
map	         Map

自定义别名

<typeAliases>
		<!-- 单个别名定义 -->
		<typeAlias alias="user" type="cn.qf.MyBatis.pojo.User" />
		<!-- 批量别名定义,扫描整个包下的类,别名为类名(大小写不敏感) -->
		<package name="com.pojo" />
		<package name="其它包" />
</typeAliases>
3 mappers(映射器)
Mapper配置的几种方法:
1. <mapper resource=" " />
使用相对于类路径的资源(现在的使用方式)
如:<mapper resource="sqlmap/User.xml" />

2. <mapper class=" " />
使用mapper接口类路径
如:<mapper class="com.mapper.UserMapper"/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

3. <package name=""/>
注册指定包下的所有mapper接口
如:<package name="com.mapper"/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

把java目录中配置也编译程序中:

<build>
<resources>
            <resource>
                <directory>src/main/resources</directory>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <!-- 是否替换资源中的属性-->
                <filtering>false</filtering>
            </resource>
  </resources>
  </build>
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值