设计软件免费下载网站,哈尔滨建设工程管理工资多少,无锡做网站多少钱,营销软件代理推广第三章 MyBatis
二、MyBatis 基本使用
4. CRUD 强化练习
4.1 准备数据库数据
首先#xff0c;我们需要准备一张名为 user 的表。该表包含字段 id#xff08;主键#xff09;、username、password。创建SQL如下#xff1a;
CREATE TABLE user (id INT(11) NOT NULL AUT…第三章 MyBatis
二、MyBatis 基本使用
4. CRUD 强化练习
4.1 准备数据库数据
首先我们需要准备一张名为 user 的表。该表包含字段 id主键、username、password。创建SQL如下
CREATE TABLE user (id INT(11) NOT NULL AUTO_INCREMENT,username VARCHAR(50) NOT NULL,password VARCHAR(50) NOT NULL,PRIMARY KEY (id)
) ENGINEINNODB AUTO_INCREMENT1 DEFAULT CHARSETutf8;4.2 实体类准备
接下来我们需要定义一个实体类 User来对应 user 表的一行数据。
Data //lombok
public class User {private Integer id;private String username;private String password;
}4.3 Mapper接口定义
定义一个 Mapper 接口 UserMapper并在其中添加 user 表的增、删、改、查方法。
public interface UserMapper {int insert(User user);int update(User user);int delete(Integer id);User selectById(Integer id);ListUser selectAll();
}4.4 MapperXML编写
在 resources /mappers目录下创建一个名为 UserMapper.xml 的 XML 文件包含与 Mapper 接口中相同的五个 SQL 语句并在其中将查询结果映射到 User 实体中。
?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapperPUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttps://mybatis.org/dtd/mybatis-3-mapper.dtd
!-- namespace等于mapper接口类的全限定名,这样实现对应 --
mapper namespacecom.alex.mapper.UserMapper!-- 定义一个插入语句并获取主键值 --insert idinsert useGeneratedKeystrue keyPropertyidINSERT INTO user(username, password)VALUES(#{username}, #{password})/insertupdate idupdateUPDATE user SET username#{username}, password#{password}WHERE id#{id}/updatedelete iddeleteDELETE FROM user WHERE id#{id}/delete!-- resultType使用user别名稍后需要配置--select idselectById resultTypeuserSELECT id, username, password FROM user WHERE id#{id}/select!-- resultType返回值类型为集合所以只写范型即可 --select idselectAll resultTypeuserSELECT id, username, password FROM user/select/mapper4.5 MyBatis配置文件
位置resources: mybatis-config.xml
?xml version1.0 encodingUTF-8 ?
!DOCTYPE configurationPUBLIC -//mybatis.org//DTD Config 3.0//ENhttp://mybatis.org/dtd/mybatis-3-config.dtd
configurationsettings!-- 开启驼峰式映射--setting namemapUnderscoreToCamelCase valuetrue/!-- 开启logback日志输出--setting namelogImpl valueSLF4J//settingstypeAliases!-- 给实体类起别名 --package namecom.alex.pojo//typeAliases!-- environments表示配置Mybatis的开发环境可以配置多个环境在众多具体环境中使用default属性指定实际运行时使用的环境。default属性的取值是environment标签的id属性的值。 --environments defaultdevelopment!-- environment表示配置Mybatis的一个具体的环境 --environment iddevelopment!-- Mybatis的内置的事务管理器 --transactionManager typeJDBC/!-- 配置数据源 --dataSource typePOOLED!-- 建立数据库连接的具体信息 --property namedriver valuecom.mysql.cj.jdbc.Driver/property nameurl valuejdbc:mysql://localhost:3306/mybatis-example/property nameusername valueroot/property namepassword valueroot//dataSource/environment/environmentsmappers!-- Mapper注册指定Mybatis映射文件的具体位置 --!-- mapper标签配置一个具体的Mapper映射文件 --!-- resource属性指定Mapper映射文件的实际存储位置这里需要使用一个以类路径根目录为基准的相对路径 --!-- 对Maven工程的目录结构来说resources目录下的内容会直接放入类路径所以这里我们可以以resources目录为基准 --mapper resourcemappers/UserMapper.xml//mappers/configuration4.6 效果测试
package com.alex.test;import com.alex.mapper.UserMapper;
import com.alex.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;import java.io.IOException;
import java.util.List;/*** projectName: com.alex.test*/
public class MyBatisTest {private SqlSession session;// junit会在每一个Test方法前执行BeforeEach方法BeforeEachpublic void init() throws IOException {session new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(mybatis-config.xml)).openSession();}Testpublic void createTest() {User user new User();user.setUsername(admin);user.setPassword(123456);UserMapper userMapper session.getMapper(UserMapper.class);userMapper.insert(user);System.out.println(user);}Testpublic void updateTest() {UserMapper userMapper session.getMapper(UserMapper.class);User user userMapper.selectById(1);user.setUsername(root);user.setPassword(111111);userMapper.update(user);user userMapper.selectById(1);System.out.println(user);}Testpublic void deleteTest() {UserMapper userMapper session.getMapper(UserMapper.class);userMapper.delete(1);User user userMapper.selectById(1);System.out.println(user user);}Testpublic void selectByIdTest() {UserMapper userMapper session.getMapper(UserMapper.class);User user userMapper.selectById(1);System.out.println(user user);}Testpublic void selectAllTest() {UserMapper userMapper session.getMapper(UserMapper.class);ListUser userList userMapper.selectAll();System.out.println(userList userList);}// junit会在每一个Test方法后执行AfterEach方法AfterEachpublic void clear() {session.commit();session.close();}
}5. mapperXML 标签总结 MyBatis 的真正强大在于它的语句映射这是它的魔力所在。由于它的异常强大映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比你会立即发现省掉了将近 95% 的代码。MyBatis 致力于减少使用成本让用户能更专注于 SQL 代码。 SQL 映射文件只有很少的几个顶级元素按照应被定义的顺序列出 insert – 映射插入语句。update – 映射更新语句。delete – 映射删除语句。select – 映射查询语句。
5.1 select 标签
MyBatis 在查询和结果映射做了相当多的改进。一个简单查询的 select 元素是非常简单
select idselectPerson
resultTypehashmap resultMap自定义结构 SELECT * FROM PERSON WHERE ID #{id} /select这个语句名为 selectPerson接受一个 int或 Integer类型的参数并返回一个 HashMap 类型的对象其中的键是列名值便是结果行中的对应值。注意参数符号#{id} ${key}MyBatis 创建一个预处理语句PreparedStatement参数在 JDBC 中这样的一个参数在 SQL 中会由一个“?”来标识并被传递到一个新的预处理语句中就像这样
// 近似的 JDBC 代码非 MyBatis 代码...
String selectPerson SELECT * FROM PERSON WHERE ID?;
PreparedStatement ps conn.prepareStatement(selectPerson);
ps.setInt(1,id);select 元素允许你配置很多属性来配置每条语句的行为细节
属性描述id在命名空间中唯一的标识符可以被用来引用这条语句。resultType期望从这条语句中返回结果的类全限定名或别名。 注意如果返回的是集合那应该设置为集合包含的类型而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。resultMap对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性如果你对其理解透彻许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个。timeout这个设置是在抛出异常之前驱动程序等待数据库返回请求结果的秒数。默认值为未设置unset依赖数据库驱动。statementType可选 STATEMENTPREPARED 或 CALLABLE。这会让 MyBatis 分别使用 StatementPreparedStatement 或 CallableStatement默认值PREPARED。
5.2 insert, update 和 delete 标签
数据变更语句 insertupdate 和 delete 的实现非常接近
insertidinsertAuthorstatementTypePREPAREDkeyPropertykeyColumnuseGeneratedKeystimeout20updateidupdateAuthorstatementTypePREPAREDtimeout20deleteiddeleteAuthorstatementTypePREPAREDtimeout20属性描述id在命名空间中唯一的标识符可以被用来引用这条语句。timeout这个设置是在抛出异常之前驱动程序等待数据库返回请求结果的秒数。默认值为未设置unset依赖数据库驱动。statementType可选 STATEMENTPREPARED 或 CALLABLE。这会让 MyBatis 分别使用 StatementPreparedStatement 或 CallableStatement默认值PREPARED。useGeneratedKeys仅适用于 insert 和 update这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键比如像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段默认值false。keyProperty仅适用于 insert 和 update指定能够唯一识别对象的属性MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值默认值未设置unset。如果生成列不止一个可以用逗号分隔多个属性名称。keyColumn仅适用于 insert 和 update设置生成键值在表中的列名在某些数据库像 PostgreSQL中当主键列不是表中的第一列的时候是必须设置的。如果生成列不止一个可以用逗号分隔多个属性名称。
三、MyBatis 多表映射
1. 多表映射概念
1.1 多表查询结果映射思路
上面讲解了单表的mybatis操作但是开发中更多的是多表查询需求这种情况我们如何该如何进行处理MyBatis 思想是数据库不可能永远是你所想或所需的那个样子。 我们希望每个数据库都具备良好的第三范式或 BCNF 范式可惜它们并不都是那样。 如果能有一种数据库映射模式完美适配所有的应用程序查询需求那就太好了而 ResultMap 就是 MyBatis 就是完美答案。官方例子我们如何映射下面这个语句
!-- 非常复杂的语句 --
select idselectBlogDetails resultMapdetailedBlogResultMapselectB.id as blog_id,B.title as blog_title,B.author_id as blog_author_id,A.id as author_id,A.username as author_username,A.password as author_password,A.email as author_email,A.bio as author_bio,A.favourite_section as author_favourite_section,P.id as post_id,P.blog_id as post_blog_id,P.author_id as post_author_id,P.created_on as post_created_on,P.section as post_section,P.subject as post_subject,P.draft as draft,P.body as post_body,C.id as comment_id,C.post_id as comment_post_id,C.name as comment_name,C.comment as comment_text,T.id as tag_id,T.name as tag_namefrom Blog Bleft outer join Author A on B.author_id A.idleft outer join Post P on B.id P.blog_idleft outer join Comment C on P.id C.post_idleft outer join Post_Tag PT on PT.post_id P.idleft outer join Tag T on PT.tag_id T.idwhere B.id #{id}
/select你可能想把它映射到一个智能的对象模型这个对象表示了一篇博客它由某位作者所写有很多的博文每篇博文有零或多条的评论和标签。 我们先来看看下面这个完整的例子它是一个非常复杂的结果映射假设作者博客博文评论和标签都是类型别名。 虽然它看起来令人望而生畏但其实非常简单。
!-- 非常复杂的结果映射 --
resultMap iddetailedBlogResultMap typeBlogconstructoridArg columnblog_id javaTypeint//constructorresult propertytitle columnblog_title/association propertyauthor javaTypeAuthorid propertyid columnauthor_id/result propertyusername columnauthor_username/result propertypassword columnauthor_password/result propertyemail columnauthor_email/result propertybio columnauthor_bio/result propertyfavouriteSection columnauthor_favourite_section//associationcollection propertyposts ofTypePostid propertyid columnpost_id/result propertysubject columnpost_subject/association propertyauthor javaTypeAuthor/collection propertycomments ofTypeCommentid propertyid columncomment_id//collectioncollection propertytags ofTypeTag id propertyid columntag_id//collection/collection
/resultMap现在可能看不懂接下来要学习将多表查询结果使用ResultMap标签映射到实体类对象上目标 多表查询语句使用多表结果承接实体类设计使用ResultMap完成多表结果映射
1.2 实体类设计方案
1.2.1 多表关系回顾双向查看
一对一 夫妻关系人和身份证号 一对多| 多对一 用户和用户的订单锁和钥匙 多对多 老师和学生部门和员工
1.2.2 实体类设计关系(查询)单向查看
1.2.2.1 对一 对一 夫妻一方对应另一方订单对应用户都是对一关系 实体类设计对一关系下类中只要包含单个对方对象类型属性即可
public class Customer {private Integer customerId;private String customerName;}public class Order {private Integer orderId;private String orderName;private Customer customer;// 体现的是对一的关系} 1.2.2.2 对多
对多: 用户对应的订单讲师对应的学生或者学生对应的讲师都是对多关系实体类设计对多关系下类中只要包含对方类型集合属性即可
public class Customer {private Integer customerId;private String customerName;private ListOrder orderList;// 体现的是对多的关系
}public class Order {private Integer orderId;private String orderName;private Customer customer;// 体现的是对一的关系}//查询客户和客户对应的订单集合 不要管!1.2.3 多表结果实体类设计小技巧
对一属性中包含对方对象对多属性中包含对方对象集合只有真实发生多表查询时才需要设计和修改实体类否则不提前设计和修改实体类无论多少张表联查实体类设计都是两两考虑!在查询映射的时候只需要关注本次查询相关的属性例如查询订单和对应的客户就不要关注客户中的订单集合
1.3 多表映射案例准备
1.3.1数据库
CREATE TABLE t_customer (customer_id INT NOT NULL AUTO_INCREMENT, customer_name CHAR(100), PRIMARY KEY (customer_id) );CREATE TABLE t_order ( order_id INT NOT NULL AUTO_INCREMENT, order_name CHAR(100), customer_id INT, PRIMARY KEY (order_id) ); INSERT INTO t_customer (customer_name) VALUES (c01);INSERT INTO t_order (order_name, customer_id) VALUES (o1, 1);
INSERT INTO t_order (order_name, customer_id) VALUES (o2, 1);
INSERT INTO t_order (order_name, customer_id) VALUES (o3, 1); 实际开发时一般在开发过程中不给数据库表设置外键约束。原因是避免调试不方便。一般是功能开发完成再加外键约束检查是否有bug。
1.3.2 实体类设计
稍后会进行订单关联客户查询也会进行客户关联订单查询所以在这先练习设计
Data
public class Customer {private Integer customerId;private String customerName;private ListOrder orderList;// 体现的是对多的关系} Data
public class Order {private Integer orderId;private String orderName;private Customer customer;// 体现的是对一的关系}