赞
踩
Mybatis的前身是Batis,他是一个持久层框架,或称为:ORM框架。
注意:所谓的框架就是别人已经写好的,对一些技术进行封装,比如:java框架一般会封装成为JAR;像其他的如JS,CSS等。而用了ORM框架,就不需要像之前操作JDBC数据库那样,一步一步进行编写,通过MyBatis可以快速的操作数据库!
DAO:Data Access Object 数据访问对象
用来对数据进行持久化操作,如将数据存入数据库、硬盘等,可以持久保存
Object Relation Mapping 对象关系映射,指的是java程序和数据库之间的映射关系
JDBC操作数据库的步骤:
在这数据库操作的一系列流程中,有些代码是不变的,有些代码是可变的
DriverClassName,URL,user,password(也称这)
这里的三个Jar包可以通过IDEA直接加载,也可以通过Maven或Gradle来进行加载
mybatis配置文件使用的是.xml文件,可以分为两大类:
主配置文件 ,在一个mybatis工程中有且只有一个,他是用来配置与整个工程配置相关的信息,如环境配置、插件配置、注册mapper文件等!
映射配置文件,在一个mybatis工程中可以有多个mapper文件,每一个mapper文件相当于原来的Dao的实现类。用来配置Dao功能的相关的SQL操作,如SQL语然啦,CRUD ,字段映射等!
注意:创建MyBatis的主配置文件时,如果一段代码需要重复利用的话,可以用模板来创建!
在这里对一个数据库进行设计;
核心配置文件,该文件一般位于src目录下,一般命名为: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>
</configuration>
<?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> <!-- TODO:配置当前项目中可能用到的所有环境! default:默认使用的环境是哪个?值指向里面的某一个--> <environments default="hello"> <!-- TODO:配置某一个具体数据库的环境,环境可以有多个! id:该环境的标识符!--> <environment id="hello"> <!-- TODO:事务管理器,他的作用是配置事务管理器 type:事务管理器的类型,取值有两种:jdbc( 简单的jdbc事务操作),JDBC默认是关闭提交事务的!conn.setAutoCommit(false) managed:将事务交给其他的框架或容器操作,如Spring--> <transactionManager type="jdbc"></transactionManager> <!-- TODO:配置数据库的连接信息 type:配置数据源。他有三个类型 UNPOOLED:使用的简单的JDBC配置,没有使用连接池技术。只有简单的连接配置 POOLED:使用了连接池技术 JNDI:通过外部容器来获取连接--> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/newdb?useSSL=false&serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> </configuration>
@Bean
public Connection connection(){
// TODO: 2021/7/26 创建一个工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
InputStream resourceAsStream = SqlSessionFactoryBuilder.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
SqlSessionFactory build = builder.build(resourceAsStream);
// TODO: 2021/7/26 创建了持久化管理器 ,所谓工厂模式,是将配置信息放入工厂,最终将创建一个持久化管理器
SqlSession sqlSession = build.openSession();
Connection connection = sqlSession.getConnection();
return connection;
}
在数据库中有一个表,那么根据ORM,那么在JAVA中就会有一个对应的类,因此,在创建映射文件的时候,首先得在Java中创建一个类;
用来配置DAO的SQL语句,每个数据库表和对应的类之间都有一个映射文件(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="abc"> <!-- TODO: insert:表示执行添加方法! id:表示执行添加操作的方法名,该方法名类似类中的方法名,是一个命名标识 如果是纯配置文件,没接口,方法名可以随便写,但必须唯一; 如果配置文件+接口的形式,id方法名的值必须与接口中一致! 这里所说的接口:是指 parameterType:表示方法的参数类型 如果是参数对象,可以使用类的全名 如果参数是变通的数据,可以使用mybatis中的别名 标签体:使用缩写的SQL语句! 使用#{XXX}表示点位符 如果参数是对象,那位占位符XXX用自定义对象中的属性名 如果参数是普通数据类型,那么占位符XXX名也就是参数名,用的是参数名这个标识指向的数据--> <insert id="insertUser" parameterType="com.dream.seeker.entity.impl.GradleUser"> insert into customer(name,salary) values (#{name},#{salary}) </insert> </mapper>
我们自定义一个映射文件,映射文件名可以自定义,那么如何告诉应用程序我们定义的映射文件呢?
Mybatis中的主配置文件m中有一个和environments平行的标签mapper。示例如下:
<mappers>
<!-- TODO:在主配置文件中,注册一个映射文件,可以有多个
resource:映射文件的路径,写的是src中的路径-->
<mapper resource="mapper/mybatis-mapper.xml"/>
</mappers>
映射文件是和主配置文件一体的文件,自定义好的映射文件(Mapper)需要在主配置文件中进行注册,映射文件有SQL语句,每个SQL语句都有类似于方法名一样的标识,我们在MyBatis中也可以称之为方法名;他还存在方法参数,该参数是Java中的一个数据对象或者普通的数据,这些对象中的属性值和普通数据就是要传入到数据库中的内容。
@Test
public void insertDate() {
gradleUser.setName("hellojava");
gradleUser.setSalary(3000);
// TODO: 2021/7/27:方式一:纯配置文件,没有接口,直接读取Mapper文件中的SQL语句!
sqlSession.insert("abc.insertUser",gradleUser);
// TODO: 2021/7/27 由于在主配置文件中,自动事务提交管理是关闭的,因此,需要手动对事务进行提交
sqlSession.commit();
}
在MyBatis中,如果需要对数据库的操作进行日志输出,则需要加载数据库日志输出依赖,并配置属性文件,具体代码如下:
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
log4j属性文件必须在类路径src下,且文件名必须命名为:log4j.properties,属性文件的具体内容可以设置如下
log4j.rootLogger=INFO,console,dailyFile # TODO 发布到阿里云记得添加,另外控制台不输出(只输出warn或者error信息) # log4j.logger.org.mybatis = INFO log4j.logger.com.imooc.mapper=INFO log4j.appender.console=org.apache.log4j.ConsoleAppender log4j.appender.console.encoding=UTF-8 log4j.appender.console.layout=org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%l] - [%p] %m%n # 定期滚动日志文件,每天都会生成日志 log4j.appender.dailyFile=org.apache.log4j.DailyRollingFileAppender log4j.appender.dailyFile.encoding=UTF-8 log4j.appender.dailyFile.Threshold=INFO # TODO 本地日志地址,正式环境请务必切换为阿里云地址 log4j.appender.dailyFile.File=C:/logs/maven-ssm-alipay/log.log4j log4j.appender.dailyFile.DatePattern='.'yyyy-MM-dd log4j.appender.dailyFile.layout=org.apache.log4j.PatternLayout log4j.appender.dailyFile.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%l] - [%p] %m%n
log4j.rootLogger=INFO,consoleAppender,logfile,MAIL log4j.addivity.org.apache=true #ConsoleAppender,控制台输出 #FileAppender,文件日志输出 #SMTPAppender,发邮件输出日志 #SocketAppender,Socket 日志 #NTEventLogAppender,Window NT 日志 #SyslogAppender, #JMSAppender, #AsyncAppender, #NullAppender #文件输出:RollingFileAppender #log4j.rootLogger = INFO,logfile log4j.appender.logfile = org.apache.log4j.RollingFileAppender log4j.appender.logfile.Threshold = INFO # 输出以上的 INFO 信息 log4j.appender.logfile.File = INFO_log.html #保存 log 文件路径 Log4j 从入门到详解 10 log4j.appender.logfile.Append = true # 默认为 true,添加到末尾,false 在每次启动时进行覆盖 log4j.appender.logfile.MaxFileSize = 1MB # 一个 log 文件的大小,超过这个大小就又会生成 1 个日志 # KB ,MB,GB log4j.appender.logfile.MaxBackupIndex = 3 # 最多保存 3 个文件备份 log4j.appender.logfile.layout = org.apache.log4j.HTMLLayout # 输出文件的格式 log4j.appender.logfile.layout.LocationInfo = true #是否显示类名和行数 log4j.appender.logfile.layout.Title =title:\u63d0\u9192\u60a8\uff1a\u7cfb\u7edf\u53d1\u751f\u4e86\u4e25\u91cd\u9519\u8b ef #html 页面的 < title > ############################## SampleLayout #################################### # log4j.appender.logfile.layout = org.apache.log4j.SampleLayout ############################## PatternLayout ################################### # log4j.appender.logfile.layout = org.apache.log4j.PatternLayout # log4j.appender.logfile.layout.ConversionPattern =% d % p [ % c] - % m % n % d ############################## XMLLayout ####################################### # log4j.appender.logfile.layout = org.apache.log4j.XMLLayout # log4j.appender.logfile.layout.LocationInfo = true #是否显示类名和行数 ############################## TTCCLayout ###################################### # log4j.appender.logfile.layout = org.apache.log4j.TTCCLayout # log4j.appender.logfile.layout.DateFormat = ISO8601 #NULL, RELATIVE, ABSOLUTE, DATE or ISO8601. # log4j.appender.logfile.layout.TimeZoneID = GMT - 8 : 00 # log4j.appender.logfile.layout.CategoryPrefixing = false ##默认为 true 打印类别名 # log4j.appender.logfile.layout.ContextPrinting = false ##默认为 true 打印上下文信息 # log4j.appender.logfile.layout.ThreadPrinting = false ##默认为 true 打印线程名 # 打印信息如下: #2007 - 09 - 13 14 : 45 : 39 , 765 [http - 8080 - 1 ] ERROR com.poxool.test.test - error 成功关闭链接 ############################################################################### #每天文件的输出:DailyRollingFileAppender #log4j.rootLogger = INFO,errorlogfile log4j.appender.errorlogfile = org.apache.log4j.DailyRollingFileAppender log4j.appender.errorlogfile.Threshold = ERROR log4j.appender.errorlogfile.File = ../logs/ERROR_log log4j.appender.errorlogfile.Append = true #默认为 true,添加到末尾,false 在每次启动时进行覆盖 log4j.appender.errorlogfile.ImmediateFlush = true #直接输出,不进行缓存 # ' . ' yyyy - MM: 每个月更新一个 log 日志 # ' . ' yyyy - ww: 每个星期更新一个 log 日志 # ' . ' yyyy - MM - dd: 每天更新一个 log 日志 # ' . ' yyyy - MM - dd - a: 每天的午夜和正午更新一个 log 日志 # ' . ' yyyy - MM - dd - HH: 每小时更新一个 log 日志 # ' . ' yyyy - MM - dd - HH - mm: 每分钟更新一个 log 日志 Log4j 从入门到详解 11 log4j.appender.errorlogfile.DatePattern = ' . ' yyyy - MM - dd ' .log ' #文件名称的格式 log4j.appender.errorlogfile.layout = org.apache.log4j.PatternLayout log4j.appender.errorlogfile.layout.ConversionPattern =%d %p [ %c] - %m %n %d #控制台输出: #log4j.rootLogger = INFO,consoleAppender log4j.appender.consoleAppender = org.apache.log4j.ConsoleAppender log4j.appender.consoleAppender.Threshold = ERROR log4j.appender.consoleAppender.layout = org.apache.log4j.PatternLayout log4j.appender.consoleAppender.layout.ConversionPattern =%d %-5p %m %n log4j.appender.consoleAppender.ImmediateFlush = true # 直接输出,不进行缓存 log4j.appender.consoleAppender.Target = System.err # 默认是 System.out 方式输出 #发送邮件:SMTPAppender #log4j.rootLogger = INFO,MAIL log4j.appender.MAIL = org.apache.log4j.net.SMTPAppender log4j.appender.MAIL.Threshold = INFO log4j.appender.MAIL.BufferSize = 10 log4j.appender.MAIL.From = yourmail@gmail.com log4j.appender.MAIL.SMTPHost = smtp.gmail.com log4j.appender.MAIL.Subject = Log4J Message log4j.appender.MAIL.To = yourmail@gmail.com log4j.appender.MAIL.layout = org.apache.log4j.PatternLayout log4j.appender.MAIL.layout.ConversionPattern =%d - %c -%-4r [%t] %-5p %c %x - %m %n #数据库:JDBCAppender log4j.appender.DATABASE = org.apache.log4j.jdbc.JDBCAppender log4j.appender.DATABASE.URL = jdbc:oracle:thin:@ 210.51 . 173.94 : 1521 :YDB log4j.appender.DATABASE.driver = oracle.jdbc.driver.OracleDriver log4j.appender.DATABASE.user = ydbuser log4j.appender.DATABASE.password = ydbuser log4j.appender.DATABASE.sql = INSERT INTO A1 (TITLE3) VALUES ( ' %d - %c %-5p %c %x - %m%n ' ) log4j.appender.DATABASE.layout = org.apache.log4j.PatternLayout log4j.appender.DATABASE.layout.ConversionPattern =% d - % c -%- 4r [ % t] %- 5p % c % x - % m % n #数据库的链接会有问题,可以重写 org.apache.log4j.jdbc.JDBCAppender 的 getConnection() 使用数 据库链接池去得链接,可以避免 insert 一条就链接一次数据库
通过IDEA可以连接MySQL数据库,连接数据库后,在编写mapper文件的时候可以有提示信息,可以防止错误的发生。在IDEA连接数据库时,一定要注意设置serverTimezone=UTC,才能正确的连接
File->Setting->Languages&Frameworks->SQL Dialects 将全局和项目的SQL Dialects都设置为:MySQL
基于接口的映射文件,他和纯配置文件的主要区别在于:
具体案例代码:
package com.dream.seeker.dao;
import com.dream.seeker.entity.impl.GradleUser;
public interface InsertUser {
public void insertUser(GradleUser user);
}
<?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="com.dream.seeker.dao.InsertUser"> <!-- TODO: insert:表示执行添加方法! id:表示执行添加操作的方法名,该方法名类似人类中的方法名,是一个命名标识 如果是纯配置文件,没接口,方法名可以随便写,但必须唯一; 如果配置文件+接口,id方法名的值必须与接口中一致! parameterType:表示方法的参数类型 如果是参数对象,可以使用类的全名 如果参数是变通的数据,可以使用mybatis中的别名 标签体:使用缩写的SQL语句! 使用#{XXX}表示点位符 如果参数是对象,那位占位符XXX用自定义对象中的属性名 如果参数是普通数据类型,那么占位符XXX名也就是参数名,用的是参数名这个标识指向的数据--> <insert id="insertUser" parameterType="com.dream.seeker.entity.impl.GradleUser"> insert into gradle(name, salary) values (#{name},#{salary}) </insert> </mapper>
@Test
public void test97() {
gradleUser.setName("hello");
gradleUser.setSalary(200);
// TODO: 2021/7/27 通过getMapper()方法,在方法中传入接口的结构信息,可以动态创建一个代理类对象
InsertUser mapper = sqlSession.getMapper(InsertUser.class);
// TODO: 2021/7/27 通过动态生成的代理类对象调用其中方法来驱动映射配置文件中的SQL语句,或者可以说:SQL语句已经动态生成到接口实现类中的方法当中
mapper.insertUser(gradleUser);
// TODO: 2021/7/27 由于在MyBatis主配置文件中,事务管理属性JDBC,因此,需要手动提交事务
sqlSession.commit();
}
知识点:通过接口 + 配置文件 的方式来操作数据库,他基本原理是:通过接口的结构信息 + 配置文件中与接口方法名相同的SQL语句,动态生成(由字节码操作工具)一个接口的实现类及实现类对象,通过这个实现类对象(代理类对象)调用对象中的方法来执行SQL语句,从而操作数据库。其主要优点是:接口动态生成的实例对象每一个方法都对应映射文件中的一个SQL语句!
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
InputStream resourceAsStream = SqlSessionFactoryBuilder.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
SqlSessionFactory build = builder.build(resourceAsStream);
// TODO: 2021/7/26 创建了持久化管理器 ,所谓工厂模式,是将配置信息放入工厂,最终将创建一个持久化管理器
SqlSession sqlSession = build.openSession();
因此,在这种情况下,我们可以创建一个工具类,返回一个持久化管理器SqlSession ,同时,需要注意的是:在工具类中,SqlSession对象必须是单例唯一的。具体示例代码如下:
public class GradleMyBatisUtils { private static SqlSessionFactory factory; // TODO: 2021/7/28 可以把ThreadLocal<>看成是一个容器,这个容器有判断hash值的方法,确定在里面的实例是否是唯一(即单例) private static ThreadLocal<SqlSession> local = new ThreadLocal<>(); static { try { factory = new SqlSessionFactoryBuilder().build( GradleMyBatisUtils.class.getClassLoader().getResourceAsStream("classpath:mybatis-config.xml") ); } catch (Exception e) { throw new ExceptionInInitializerError("MyBatis初始化失败" + e.getMessage()); } } // TODO: 2021/7/28 获取一个持久化管理器,管理器里包数据库连接池,事务和数据库连接的相关信息,具体内容和配置文件中有关 public static SqlSession getSession(){ // TODO: 2021/7/28 从容器中获得对象, 由于是单例的,所以,会依据类型进行匹配 SqlSession sqlSession = local.get(); if (sqlSession == null) { sqlSession = factory.openSession(); local.set(sqlSession); } return sqlSession; } // TODO: 2021/7/28 关闭持久化管理对象,关闭此对象,会同时关闭数据库连接池中相关对象,如connection,statement等! public static void close(){ SqlSession sqlSession = local.get(); if (sqlSession!=null) { sqlSession.close(); local.remove(); } } }
新增知识点:在工具类中,我们可以用ThreadLocal类实例来管理工具类中对象是否为单例,ThreadLocal实例具有存储和管理工具类中指定对象类型的功能,可以用来判断工具类中主对象是否为空,如果不为空的话,可以通过get()方法直接获得相应的对象。
@Test public void test110() { SqlSession sqlSession = null; try { // TODO: 2021/7/28 从工具类中获得持欠化管理器 sqlSession = MyBatisUtils.getSession(); // TODO: 2021/7/28 下面几段代码是具体对数据库进行操作的代码 GradleUser gradleUser = new GradleUser(); gradleUser.setName("hellojava"); gradleUser.setSalary(5000); InsertUser mapper = sqlSession.getMapper(InsertUser.class); mapper.insertUser(gradleUser); // TODO: 2021/7/28 由于事务采取的方式是JDBC方式,他自动提交是关闭的,因此,需要手动关闭 sqlSession.commit(); } catch (Exception e) { e.printStackTrace(); // TODO: 2021/7/28 如果发生异常,事务没有执行完,地么需要回滚操作 sqlSession.rollback(); } finally { MyBatisUtils.close(); } }
在主配置文件中,添加标签选项:typeAliases,可以为java类对象设置别名(这个JAVA类对象是存储数据库信息的Bean,使用此类对象设置数据,再将此类对象中的数据传入到数据库),这个java类对象是执行SQL方法中的参数,这个参数他位于MyBatis映射文件中。设置别名主要是在MyBatis主配置文件中,使用标签typeAliases,具体示例如下:
<!-- TODO:设置别名 -->
<typeAliases>
<!-- TODO:为某一个类去配置别名 -->
<!-- <typeAlias type="com.dream.seeker.entity.impl.GradleUser" alias="GradleUser"/>-->
<!-- TODO:package:为包下面的所有类取别名
name:指定包名,该包下所有类的别名,就是其自身的类名,原则上不区分大小上,但建设采用首字母大写-->
<package name="com.dream.seeker.entity.impl"/>
</typeAliases>
设置好别名后,那么就可以在MyBatis映射文件中使用别名了,下面的代码是基于接口 + 配置文件的方式定义的mapper(映射)文件,其中namesapce是接口名,id指的是接口的抽象方法名,而parameterType这个地方通过在主配置文件中定义的别名,可以简化许多代码。
<?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="com.dream.seeker.dao.InsertUser"> <!-- TODO: insert:表示执行添加方法! id:表示执行添加操作的方法名,该方法名类似人类中的方法名,是一个命名标识 如果是纯配置文件,没接口,方法名可以随便写,但必须唯一; 如果配置文件+接口,id方法名的值必须与接口中一致! parameterType:表示方法的参数类型 如果是参数对象,可以使用类的全名 如果参数是变通的数据,可以使用mybatis中的别名 标签体:使用缩写的SQL语句! 使用#{XXX}表示点位符 如果参数是对象,那位占位符XXX用自定义对象中的属性名 如果参数是普通数据类型,那么占位符XXX名也就是参数名,用的是参数名这个标识指向的数据--> <insert id="insertUser" parameterType="GradleUser"> insert into gradle(name, salary) values (#{name},#{salary}) </insert> </mapper>
在属性文件中写连接信息,首先得定义一个属性文件xxxx.properties,将相关的连接信息写入到里面,案例如下:
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/newdb?serverTimezone=UTC&useSSL=false
jdbc.username=root
jdbc.password=123456
在定义完属性文件后,需要在MyBatis的主配置文件中将自定义的属性文件添加到主配置文件中,在主配置文件中,用到了标签:properties,具体代码案例如下:
<properties resource="dbcp.properties"/>
在MyBatis主配置文件中定义好了属性文件后,则可以改写主配置文件中的连接信息,改写的内容采用 表 达 式 , 连 接 信 息 也 是 通 过 属 性 后 置 处 理 器 的 结 {}表达式,连接信息也是通过属性后置处理器的结 表达式,连接信息也是通过属性后置处理器的结{}表达式进行转换,具体代码案例如下:
<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>
基于接口 + 配置文件 的方式对数据库进行插入操作SQL时,一般情况下是不返回主键的,如果需要返回主键,那么需要在mapper文件中添加属性:userGeneratedKey。此属性的作用是保留进行插入SQL操作时的主键,此主键的值保存在哪个位置呢?答案是:保存到方法参数对象的属性中,然而,自定义的参数对象有许多属性,他又会保存到哪个属性当中呢,这时,在mapper文件中,又需要用到一个属性名为
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。