MyBatis01-MyBatis入门程序
一、JDBC 的主要问题缺点虽然 JDBC 是 Java 操作数据库的标准方式但它存在很多痛点1.代码冗余严重每次操作数据库都要写很多重复代码如建立连接创建PreparedStatement设置参数执行 SQL处理结果集ResultSet关闭资源Connection conn DriverManager.getConnection(...); PreparedStatement ps conn.prepareStatement(SELECT * FROM user WHERE id ?); ps.setInt(1, id); ResultSet rs ps.executeQuery(); ...每次都要写这些重复操作非常容易出错。2.SQL 和 Java 代码混杂维护困难SQL 都是写在 Java 字符串里比如String sql SELECT * FROM user WHERE id id;这会导致SQL 写错编译器不会报错因为是字符串不利于团队中 DBA 和开发协作SQL 不容易复用也不清晰3.参数设置和结果映射繁琐你要手动setXxx()设置参数要从ResultSet一行行取数据再封装对象User user new User(); user.setId(rs.getInt(id)); user.setName(rs.getString(name));对每个表、每个查询都要这样写非常麻烦且容易出错。4.没有内置的缓存机制JDBC 本身不提供缓存每次访问都得查数据库性能难以优化。二、引出 MyBatis —— 轻量级 ORM 框架MyBatis 是为了解决 JDBC 繁琐问题而诞生的。它是一个半自动 ORM 框架Object Relational Mapping 对象关系映射专注于 SQL 映射和自动结果封装。三、ORM对象关系映射ORM: 对象 关系 映射O (Object): JVM 中的 java 对象R (Relational): 关系型数据库M (Mapping): 映射MyBatis 框架就是一个ORM 框架。MyBatis 可以干啥java 对象 ----- 数据库表中的一条记录MyBatis 是一个半自动化的 ORM因为 MyBatis 框架中 SQL 语句是需要程序员自己编写的。Hibernate 框架就是一个全自动化的 ORM。使用 Hibernate 框架的时候不需要程序员手动编写 SQL 语句SQL 语句可以自动生成。所以 Hibernate 是一个完全的全自动化的 ORM 框架。在 ORM对象关系映射领域区分“全自动”和“半自动”的最直观标准是看框架是否包揽了 SQL 语句的生成工作。全自动ORM的缺点开发者失去了对 SQL 的直接控制权。当遇到复杂的联表查询、或者需要极致优化某一条 SQL 性能时Hibernate 自动生成的 SQL 往往比较臃肿调优门槛极高。半自动体现在哪里它映射的不是对象和表而是Java 方法和具体的 SQL 语句。你必须自己手写 SQL例如SELECT * FROM user WHERE id #{id}。MyBatis 这个“半自动机器”只帮你做两件事输入映射把你传进去的 Java 参数如 Integer, String, Object自动拼接到 SQL 里。输出映射帮把数据库返回的 ResultSet 结果集自动封装成你想要的 Java 对象。四、MyBatis 能做什么优势1.自动封装结果集 → Java 对象你只需要定义一个 SQL 映射它会自动将查询结果封装成 Java Beanselect idgetUserById parameterTypeint resultTypeUser SELECT * FROM user WHERE id #{id} /selectMyBatis 自动帮你完成SQL 执行参数填充ResultSet → User封装2.SQL 写在 XML 或注解中清晰好维护SQL 和 Java 分离DBA 可以直接看 SQL 文件业务逻辑更清爽3.支持动态 SQL 和映射配置你可以写条件查询、动态拼接 SQLselect idfindUsers resultTypeUser SELECT * FROM user where if testname ! null AND name #{name} /if if testage ! null AND age #{age} /if /where /select动态sql:SQL 不是固定写死的而是根据你传进来的条件临时拼接出不同的 SQL。重点是查询条件不同最终执行的 SQL 也不同。4.缓存支持MyBatis 提供一级缓存二级缓存可选提高性能。5.简化开发节省大量模板代码你不再需要手动写ResultSet→ 对象的转换MyBatis 帮你搞定。五、MyBatis入门程序的开发5-1、示例1、准备数据库表汽车表 t_car字段包括id: 主键 (自增)【bigint】car_num: 汽车编号【varchar】brand: 品牌【varchar】guide_price: 厂家指导价【decimal 类型专门为财务数据准备的类型】produce_time: 生产时间【char, 年月日即可10 个长度2022 - 10 - 11】car_type: 汽车类型 (燃油车、电车、氢能源)【varchar】CREATE TABLE t_car ( id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 主键ID自增, car_num VARCHAR(50) DEFAULT NULL COMMENT 汽车编号, brand VARCHAR(50) DEFAULT NULL COMMENT 品牌, guide_price DECIMAL(10, 2) DEFAULT NULL COMMENT 厂家指导价单位元, produce_time CHAR(10) DEFAULT NULL COMMENT 生产时间格式如2022-10-11, car_type VARCHAR(20) DEFAULT NULL COMMENT 汽车类型燃油车、电车、氢能源 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT汽车信息表;创建一个项目直接放在resources目录下的资源等同于放到了类的根路径下。“类的根路径”其实就是程序运行时JVM / 类加载器查找.class文件和资源文件的起点位置。它也经常叫classpath 根路径中文可以理解成类路径的根目录2、开发步骤第一步打包方式 jar第二步引入依赖mybatis 依赖mysql 驱动依赖!-- 打包方式 -- packagingjar/packaging !-- 添加依赖 -- dependencies !-- mybatis依赖 -- dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version3.5.7/version /dependency !-- mysql驱动依赖 -- dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId version8.3.0/version /dependency /dependencies第三步编写 mybatis 核心配置文件mybatis-config.xml?xml version1.0 encodingUTF-8 ? !DOCTYPE configuration PUBLIC -//mybatis.org//DTD Config 3.0//EN http://mybatis.org/dtd/mybatis-3-config.dtd configuration environments defaultdevelopment environment iddevelopment transactionManager typeJDBC/ dataSource typePOOLED property namedriver valuecom.mysql.jdbc.Driver/ property nameurl valuejdbc:mysql://localhost:3306/wsbazinga/ property nameusername valueroot/ property namepassword value/ /dataSource /environment /environments !-- 执行XxxMapper.xml文件的路径 -- !-- resource路径自动会从根路径下开始查找资源 -- mappers mapper resourceCarMapper.xml/ /mappers /configuration【注意】第一这个文件名不是必须叫做 mybatis-config.xml可以用其他的名字。只是大家都采用这个名字。第二这个文件存放的位置也不是固定的可以随意但一般情况下会放到类的根路径resource下。第四步编写XxxxMapper.xml文件在这个文件中编写sql语句?xml version1.0 encodingUTF-8 ? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacejfkdjfdkfj insert idinsertCar INSERT INTO t_car (car_num, brand, guide_price, produce_time, car_type) VALUES (CAR20250710A, Toyota, 15.80, 2024-12-01, 燃油车); /insert /mapper第五步在 mybatis-config.xml中指定XxxxMapper.xml文件的路径。第六步编写Mybatis程序使用Mybatis类库编写Mybatis程序连接数据库做增删改查。public static void main(String[] args) throws Exception{ // 获取sqlSessionFactoryBuilder对象 SqlSessionFactoryBuilder sqlSessionFactoryBuilder new SqlSessionFactoryBuilder(); // 获取SqlSessionFactory对象 InputStream resourceAsStream Resources.getResourceAsStream(mybatis-config.xml); // 一般一个数据库对应一个SqlSessionFactory对象 SqlSessionFactory sqlSessionFactory sqlSessionFactoryBuilder.build(resourceAsStream); // 获取SqlSession对象 SqlSession sqlSession sqlSessionFactory.openSession(); // 执行sql语句insertCar是sql语句的id int count sqlSession.insert(insertCar); System.out.println(插入了几条数据 count); // 手动提交 sqlSession.commit(); }在MyBatis当中负责执行SQL语句的那个对象叫做什么呢SqlSessionSqlSession是专门用来执行SQL语句的是一个Java程序和数据库之间的一次会话。要想获取SqlSession对象需要先获取SqlSessionFactory对象通过SqlSessionFactory工厂来生产SqlSession对象。怎么获取SqlSessionFactory对象呢需要首先获取SqlSessionFactoryBuilder对象。 通过SqlSessionFactoryBuilder对象的build方法来获取一个SqlSessionFactory对象。mybatis的核心对象包括 SqlSessionFactoryBuilder、SqlSessionFactory、SqlSessionSqlSessionFactoryBuilder -- SqlSessionFactory -- SqlSession3、从 XML 中构建 SqlSessionFactory通过官方的这句话你能想到什么呢第一在 MyBatis 中一定是有一个很重要的对象这个对象是SqlSessionFactory 对象。第二SqlSessionFactory 对象的创建需要 XML。XML一定是一个配置文件。4、mybatis 中有两个主要的配置文件一个是mybatis-config.xml这是核心配置文件主要配置连接数据库的信息等。一个另一个是XxxxMapper.xml这个文件是专门用来编写 SQL 语句的配置文件。一个表一个t_user 表一般会对应一个 UserMapper.xmlt_student 表一般会对应一个 StudentMapper.xml5-2、关于第一个程序的小细节1、mybatis中sql语句的结尾;可以省略。2、Resources.getResourceAsStream小技巧// 获取SqlSessionFactory对象 InputStream resourceAsStream Resources.getResourceAsStream(mybatis-config.xml); // 一般一个数据库对应一个SqlSessionFactory对象 SqlSessionFactory sqlSessionFactory sqlSessionFactoryBuilder.build(resourceAsStream);以后凡是遇到resource这个单词大部分情况下这种加载资源的方式就是从类的根路径下开始加载。开始查找优点采用这种方式从类路径当中加载资源项目的移植性很强。项目从windows移植到linux代码不需要修改因为这个资源文件一直都在类路径当中。InputStream is new FileInputStream(d:\\mybatis-config.xml);采用这种方式也可以。缺点可移植性太差程序不够健壮。可能会移植到其他的操作系统当中。导致以上路径无效还需要修改java代码中的路径。这样违背了OCP开闭原则。3、已经验证了1mybatis核心配置文件的名字不一定是mybatis-config.xml。可以是其它名字。2mybatis核心配置文件存放的路径也不一定是在类的根路径下。可以放到其它位置。但为了项目的移植性健壮性最好将这个配置文件放到类路径下面。4、InputStream is ClassLoader.getSystemClassLoader().getResourceAsStream(mybatis-config.xml);ClassLoader.getSystemClassLoader() 获取系统的类加载器。系统类加载器有一个方法叫做getResourceAsStream 它就是从类路径当中加载资源的。通过源代码分析发现 InputStream is Resources.getResourceAsStream(mybatis-config.xml); 底层的源代码其实就是 InputStream is ClassLoader.getSystemClassLoader().getResourceAsStream(mybatis-config.xml);5、CarMapper.xml文件的名字是固定的吗CarMapper.xml文件的路径是固定的吗都不是固定的。6、!-- 执行XxxMapper.xml文件的路径 -- !-- resource路径自动会从根路径下开始查找资源 -- mappers mapper resourceCarMapper.xml/ /mappersresource属性这种方式是从类路径当中加载资源。mapper urlfile:///d:/CarMapper.xml/url属性这种方式是从绝对路径当中加载资源。移植性差六、关于mybatis的事务管理机制在mybatis-config.xml文件中可以通过以下的配置进行mybatis的事务管理type属性的值包括两个JDBC(jdbc)MANAGED(managed)type后面的值只有以上两个值可选不区分大小写。在mybatis中提供了两种事务管理机制第一种JDBC事务管理器第二种MANAGED事务管理器1JDBC事务管理器mybatis框架自己管理事务自己采用原生的JDBC代码去管理事务conn.setAutoCommit(false); //开启事务。 //.....业务处理... conn.commit(); //手动提交事务MyBatis 自己调用 JDBC 的Connection来提交和回滚事务。示例SqlSession sqlSession sqlSessionFactory.openSession(); try { mapper.insertUser(user); mapper.updateAccount(account); sqlSession.commit(); } catch (Exception e) { sqlSession.rollback(); }这里的commit()和rollback()是有效的。2MANAGED事务管理器mybatis不再负责事务的管理了。事务管理交给其它容器来负责。例如spring。对于我们当前的单纯的只有mybatis的情况下如果配置为MANAGED那么事务这块是没人管的。没有人管理事务表示事务压根没有开启。所以也不需要手动提交insert会进入数据库自动提交。【注意】只要autoCommit是true自动就表示没有开启事务。只有autoCommit是false表示开启了事务。配置谁管理事务适合场景typeJDBCMyBatis 自己通过 JDBC 管理事务单纯 MyBatis 项目typeMANAGED外部容器管理事务Spring / Java EE / JTA 环境3、没有开启事务的两种情况情况一单纯的mybatis项目没有 Spring没有 Java EE 容器也没有其他事务管理器。type的值是managed。情况二红字里说“没有开启事务”意思是说因为每一条 SQL 执行完就立刻自动提交了所以实际上也就失去了把多条 SQL 捆绑在一起同时成功或同时失败的“事务控制”能力。typeJDBC只是说明MyBatis 有能力用 JDBC 来管理事务。真正是否自动提交要看openSession()里面传不传true。SqlSession sqlSession sqlSessionFactory.openSession();这句等价于SqlSession sqlSession sqlSessionFactory.openSession(false);也就是默认不是自动提交。所以openSession()意思是开启一个 SqlSession并且关闭自动提交。之后的 SQL 需要你手动commit()或rollback()。所以SqlSession sqlSession sqlSessionFactory.openSession(true);意思是开启自动提交。七、一个完整的Mybatis程序public static void main(String[] args) { SqlSession sqlSession null; try { SqlSessionFactoryBuilder sqlSessionFactoryBuilder new SqlSessionFactoryBuilder(); SqlSessionFactory sqlSessionFactory sqlSessionFactoryBuilder.build(Resources.getResourceAsStream(mybatis-config.xml)); // 开启会话底层是开启事务 sqlSession sqlSessionFactory.openSession(); // 执行sql语句处理相关业务 int count sqlSession.insert(insertCar); System.out.println(count); // 执行到这里没有发生任何异常提交事务终止事务 sqlSession.commit(); } catch (IOException e) { // 发生异常回滚事务 if(sqlSession ! null){ sqlSession.rollback(); } e.printStackTrace(); } finally { // 关闭会话释放资源 sqlSession.close(); } }八、Mybatis集成JUnit目的进行单元测试步骤一pom.xml中添加依赖!-- junit依赖 -- dependency groupIdjunit/groupId artifactIdjunit/artifactId version4.13.2/version scopetest/scope /dependency编写业务类/** * 数学业务类 */ public class MathService { /** * 求和业务方法 * param a * param b * return */ public int sum(int a, int b){ return a b; } /** * 作差业务方法 * param a * param b * return */ public int sub(int a, int b){ return a - b; } }编写业务类对应的单元测试方法编写测试方法/** * 单元测试类 */ public class MathServiceTest { Test public void testSum(){ MathService mathService new MathService(); // 真实值 int actual mathService.sum(1, 3); // 期望值 int expected 4; // 断言 Assert.assertEquals(expected, actual); } Test public void testSub(){ MathService mathService new MathService(); // 真实值 int actual mathService.sub(5, 3); // 期望值 int expected 2; // 断言 Assert.assertEquals(expected, actual); } }九、 Mybatis集成日志框架1、STDOUT_LOGGING标准日志关于mybatis集成日志组件让我们调试起来更加方便可以看到控制台打印的sql语句。mybatis常见的集成的日志组件有哪些呢SLF4J沙拉风沙拉风是一个日志标准其中有一个框架叫logback它实现了沙拉风规范。 LOG4J LOG4J2 STDOUT_LOGGING ....【注意】log4j、log4j2、logback是同一个作者其中STDOUT_LOGGING是标准日志mybatis框架本身已经实现了这种标准日志。只要开启即可。怎么开启呢在mybatis-config.xml文件中使用settings标签进行配置开启。这个标签在编写的时候要注意它应该出现在environments标签之前注意顺序。当然不需要记忆这个顺序。因为有dtd文件进行约束呢。我们只要参考dtd约束即可。若是需要引入别的日志框架settings标签可以不写STDOUT_LOGGING这种实现也是可以的可以看到一些信息比如连接对象什么时候创建什么时候关闭sql语句是怎样的。但是没有详细的日期线程名字等。如果你想使用更加丰富的配置可以集成第三方的log组件。2、集成logback日志框架logback日志框架实现了slf4j标准。沙拉风日志门面。日志标准。第一步引入logback的依赖。第二步引入logback所必须的xml配置文件?xml version1.0 encodingUTF-8? configuration appender nameCONSOLE classch.qos.logback.core.ConsoleAppender encoder pattern%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n/pattern /encoder /appender appender nameFILE classch.qos.logback.core.rolling.RollingFileAppender encoder pattern%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n/pattern charsetutf-8/charset /encoder filelog/output.log/file rollingPolicy classch.qos.logback.core.rolling.FixedWindowRollingPolicy fileNamePatternlog/output.log.%i/fileNamePattern /rollingPolicy triggeringPolicy classch.qos.logback.core.rolling.SizeBasedTriggeringPolicy MaxFileSize1MB/MaxFileSize /triggeringPolicy /appender root levelDEBUG appender-ref refCONSOLE / appender-ref refFILE / /root /configuration这个配置文件的名字必须叫做logback.xml或者logback-test.xml不能是其它的名字这个配置文件必须放到类的根路径下不能是其他位置十、Mybatis工具类的编写原因每一次创建对象都要写以下代码SqlSessionFactoryBuilder sqlSessionFactoryBuilder new SqlSessionFactoryBuilder(); SqlSessionFactory sqlSessionFactory sqlSessionFactoryBuilder.build(Resources.getResourceAsStream(mybatis-config.xml)); // 开启会话底层是开启事务 sqlSession sqlSessionFactory.openSession(); // 执行sql语句处理相关业务 // int count sqlSession.insert(insertCar);所以封装一个工具类直接返回sqlSession一个SqlSessionFactory对象对应一个environment一个environment通常是一个数据库。/** * mybatis工具类 */ public class SqlSessionUtils { private static SqlSessionFactory sqlSessionFactory; // 工具类中的构造方法都是private目的防止创造对象 private SqlSessionUtils(){ } // 类加载时执行 // SqlSessionUtils工具类在进行第一次加载的时候解析mybatis-config.xml文件创建sqlSessionFactory对象 static { try { sqlSessionFactory new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(mybatis-config.xml)); } catch (IOException e) { e.printStackTrace(); } } // 工具类中所有的方法都是静态的目的直接采用类名即可调用不用new public static SqlSession openSession(){ SqlSession sqlSession sqlSessionFactory.openSession(); return sqlSession; } }十一、使用Mybatis完成CRUD11-1、insert1、什么是CRUDCCreate增RRetrieve查检索UUpdate改DDelete删insert idinsertCar INSERT INTO t_car (car_num, brand, guide_price, produce_time, car_type) VALUES (CAR20250710A, Toyota, 15.80, 2024-12-01, 燃油车); /insert这样写的问题是值 显然是写死到配置文件中的。这个在实际开发中是不存在的。 一定是前端的form表单提交过来数据。然后将值传给sql语句。2、使用Map集合给占位符传值在JDBC当中占位符采用的是?在mybatis当中是什么呢 和?等效的写法是#{}在mybatis当中不能使用?占位符必须使用 #{} 来代替JDBC当中的 ?#{} 和 JDBC当中的 ? 是等效的。java程序中使用Map可以给SQL语句的占位符传值【注意】#{这里写什么写map集合的key如果key不存在获取的是null}3、使用 POJO类给占位符传值java程序中使用POJO类给SQL语句的占位符传值Test public void pojoTest(){ Car car new Car(null, 3333, 比亚迪秦, 30.0, 2020-11-11, 新能源); SqlSession sqlSession SqlSessionUtils.openSession(); int count sqlSession.insert(insertCar, car); System.out.println(count); sqlSession.commit(); sqlSession.close(); }注意占位符#{}大括号里面写pojo类的属性名insert into t_car (id,car_num,brand,guide_price,produce_time,car_type) values (null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})把SQL语句写成这个德行出现了什么问题呢There is nogetterfor property named xyz in class com.powernode.mybatis.pojo.Carmybatis去找Car类中的getXyz()方法去了。没找到。报错了。怎么解决的可以在Car类中提供一个getXyz()方法。这样问题就解决了。【小结】通过这个测试得出一个结论严格意义上来说如果使用POJO对象传递值的话#{}这个大括号中写的是get方法的方法名去掉get然后将剩下的单词首字母小写然后放进去。例如getUsername() -- #{username}例如getEmail() -- #{email}.....11-2、delete11-3、updateTest public void testUpdateById(){ SqlSession sqlSession SqlSessionUtils.openSession(); // 准备数据 Car car new Car(3L, 3333, 比亚迪秦, 30.0, 2020-11-11, 新能源); // 执行sql语句 int count sqlSession.update(updateById, car); System.out.println(count); sqlSession.commit(); sqlSession.close(); }11-4、select1、select查一个需求根据主键查询的话返回的结果一定是一个。实现需要特别注意的是 select标签中resultType属性这个属性用来告诉mybatis查询结果集封装成什么类型的java对象。resultType通常写的是全限定类名。Car{id1, carNumnull, brand宝马520Li, guidePricenull, produceTimenull, carTypenull} 输出结果有点不对劲 id和brand属性有值。 其他属性为null。carNum以及其他的这几个属性没有赋上值的原因是什么2、Select查所有select idselectAll resultTypecom.wsbazinga.pojo.Car select id, car_num as carNum, brand, guide_price as guidePrice, produce_time as produceTime, car_type as carType from t_car /select【注意】resultType的类型是List集合中的对象的类型十二、namespace的作用在mapper.xml文件中有一个namespace这个属性是用来指定命名空间的用来防止不同 mapper 里的 SQL 的 id 重名。在xml文件中想要调idinsertCar的sql可以这样访问int count sqlSession.insert(jfkdjfdkfj.insertCar);实际上mybatis中sql的完整写法namespace.id。目的区分不同的mapper.xml文件中的sql语句对应的id是重复的十三、MyBatis中的驼峰映射问题问题MyBatis 不会把 SQL 里的car_name自动替换成carName。car_name -- 数据库表字段名#{carName} -- Java 对象属性名查询时默认也不一定自动映射。比如你写select car_name from t_carJava 类里是private String carName;默认情况下MyBatis 可能不知道car_name 对应 carName所以常见有三种解决方法。方法一SQL 里起别名这是最直接的select car_name as carName from t_car这样 MyBatis 看到的结果列名就是carName。就可以对应 Java 属性private String carName;方法二开启驼峰映射在mybatis-config.xml中配置settings setting namemapUnderscoreToCamelCase valuetrue/ /settings开启后MyBatis 可以把查询结果里的car_name 自动映射到 Java 属性carName。但是注意这是结果映射不是把 SQL 文本里的car_name改成carName。方法三使用 resultMapresultMap idcarResultMap typeCar result propertycarName columncar_name/ /resultMap意思是数据库字段 car_name 对应 Java属性 carName。

相关新闻