# 数据库强化 ## 四、触发器 #### 1、触发器语法 ##### 创建触发器 ```sql CREATE TRIGGER 触发器名 触发时机 触发事件 ON 表 FOR EACH ROW BEGIN -- SQL代码 END; ``` 触发事件:`insert`、`update`、`delete` 触发时机:`before`、`after` `FOR EACH ROW`:对于其中的每个数据行,只要符合触发条件,就激活一次(行级触发器)。 ##### 删除触发器 ```sql DROP TRIGGER 触发器名; ``` ##### 查看触发器 ```sql SHOW TRIGGERS; ``` #### 2、触发器示例 ##### 触发器实现主表与外键表联级删除 ```sql CREATE TRIGGER dept_del BEFORE DELETE ON DEPT FOR EACH ROW BEGIN DELETE FROM EMP WHERE EMP.DEPTno = OLD.DEPTno; END; DELETE FROM DEPT WHERE DEPT.DEPTno=1; ``` **注意**:此处用来判断的要删除表需要用`OLD`来代替,不能直接写表名。、 ## 五、数据库优化 #### 1、适度的违反范式 在开发应用程序时,数据库设计要最大程度的遵守三范式。当 然,三范式最大的问题在于查询时通常需要join很多表,导致查询效率很低。所以有时候基于性能考虑,我们需要有意的违反三范式。也就是适度的做冗余,以达到提高查询效率的目的。注意这里的反范式是适度的。 #### 2、适当建立索引 索引可以有效的提高查询速度,但这个提高是以插入、更新、删除的速度为代价的。由于索引的存储结构不同于表的存储,一个表的索引所占空间比可能数据所占空间还大。这意味着我们在写数据库的时候做了很多额外的工作,而这个工作只是为了提高读的效率。因此,我们建立一个索引,必须保证这个索引不会“亏本”。一般需要遵守这样的规则: * 对经常更新的表就避免对其进行过多的索引。 * 对经常用于查询的字段应该创建索引。 * 数据量小的表最好不要使用索引。 * 相同值较多的字段上不要建立索引(比如"性别"字段)。相反的,在不同值较多的字段上可以建立索引。 #### 3、对表进行水平划分 如果一个表的记录数太多了,比如上千万条,而且需要经常检索,那么我们就有必要化整为零了。如果我拆成100个表,那么每个表只有10万条记录。当然这 需要数据在逻辑上可以划分。一个好的划分依据,有利于程序的简单实现,也可以充分利用水平分表的优势。 比如系统界面上只提供按月查询的功能,那么把表按月拆分成12个,每个查询只查询一个表就够了。 #### 4、对表进行垂直划分 有些表记录数并不多,但是字段却很多,导致表占用空间很大,检索表时需要执行大量I/O,严重降低了性能。解决方案是:可以把一部分字段拆分到另一个表,并且该表与原表是一对一的关系。 #### 5、选择合适的引擎 在Oracle和SQL Server等数据库中只有一种存储引擎,所有数据存储管理机制都是一样的。而MySQL数据库提供了多种存储引擎,用户可以根据不同的需求为数据表选择不同的存储引擎。比如: * InnoDB存储引擎支持外键、支持事务、支持全文检索; * MyISAM存储引擎可以被压缩、不支持事务、不支持外键;如果需要执行大量的select语句,MyISAM存储引擎是更好的选择。 * MEMORY存储引擎主要用于那些内容稳定的表,或者作为统计操作的中间表。 ## 六、SQL语句优化 #### 1、尽量使用批量操作 尽量使用MySql中的批量操作语句,这样可以避免频繁读写操作。比如:批量插入、批量更新、批量删除。 ```sql /* 使用多个insert语句效率低 */ insert into dept values(null,'技术部','沈阳市'); insert into dept values(null,'销售部','上海市'); insert into dept values(null,'总部','北京市'); /* 使用批量insert语句效率高 */ insert into dept values(null,'技术部','沈阳市'),(null,'销售部','上海市'),(null,'总部','北京市'); ``` #### 2、选择适当的数据类型 选择字段的数据类型的一般原则是尽量使用占用字节小的数据类型。 比如主键, 强烈建议用自增类型,既节省空间,又能满足大多数需求。 #### 3、文件、图片等大文件用文件系统存储,不要使用数据库 数据库只存储文件路径。这是一个基本原则! #### 4、使用连接(JOIN)来代替子查询(Sub-Queries) MySQL从4.1开始支持SQL的子查询。但是,子查询可以被更有效率的连接替代。连接之所以更有效率一些,是因为MySQL不需要在内存中创建临时表来完成需要多个步骤才能完成的子查询。 ```sql /* 查询部门地址在"NEW YORK"的所有员工 */ /* 子查询方式效率低 */ select * from emp where deptno in(select deptno from dept where loc='NEW YORK') /* 多表连接方式效率高 */ select e.* from emp e,dept d where e.deptno=d.deptno and d.loc='NEW YORK' ``` #### 5、对查询语句进行优化 绝大多数情况下,使用索引可以提高查询的速度,但如果SQL语句使用不恰当的话,索引将无法发挥它应有的作用。下面是应该注意的几个方面。 * 首先,最好是在相同类型的字段间进行比较的操作,可以避免转型的步骤。 * 其次,在建有索引的字段上尽量不要使用函数进行操作。使用函数后索引将失效。 * 在搜索字符型字段时,我们有时会使用LIKE关键字和通配符,这种做法虽然简单,但却也是以牺牲系统性能为代价的。 * 应该注意避免在查询中让MySQL进行自动类型转换,因为转换过程也会使索引变得不起作用。 ## 七、数据库参数配置优化 MySql安装之后,默认参数并不能满足所有生产场合下的需求。所以,还需要根据需求,修改Mysql服务器的系统参数,达到合理利用服务器现有资源,最大合理的提高MySQL性能。比如: * wait_timeout:MySQL客户端的数据库连接闲置最大时间值。 * max_connections:MySQL的最大连接数。 * max_user_connections:每个数据库用户的最大连接。 * thread_concurrency:线程最大并发数。 * default-storage-engine:设置MySQL默认存储引擎 ```sql -- 查询MySQL的最大连接数。 show global variables like '%max_connections%'; -- 设置MySQL的最大连接数。 set global max_connections=1024; ``` ## 八、硬件和系统的优化 #### 1、合理采用操作系统 如果服务器内存超过4G,那么毋庸置疑应当采用64位操作系统和64位mysql #### 2、读写分离 如果数据库压力很大,一台机器支撑不了,那么可以用mysql复制实现多台机器同步,将数据库的压力分散。 比如:主库用来写入,从库都用来做select,那么每个数据库分担的压力小了很多。当然,要实现这种方式,需要程序特别设计,给程序开发带来了额外负担。不过现在已经有中间件来实现这些功能。 --- # Maven ## 一、Maven安装与配置 具体内容见[MyBatis框架基础](https://soki.me/archives/237.html)的第一条。 --- # MyBatis 此处知识点与[MyBatis框架基础](https://www.soki.me/archives/237.html)内容高度重复,只是用来记录上课流程,更加详细的内容请参考前面文章。 ## 一、ORM思想 数据库中数据是以表的形式存在的,而java中使用的数据都是对象型的。所以不得不要将表数据转换成对象数据。 这样就会产生大量的没有技术含量的纯 “体力” 型代码。 ```java while(rs.next()) { Business business = new Business(); business.setBusinessId(rs.getInt("businessId")); business.setPassword(rs.getString("password")); business.setBusinessName(rs.getString("businessName")); business.setBusinessAddress(rs.getString("businessAddress")); business.setBusinessExplain(rs.getString("businessExplain")); business.setStarPrice(rs.getDouble("starPrice")); business.setDeliveryPrice(rs.getDouble("deliveryPrice")); list.add(business); } ``` 上面代码就属于纯 “体力” 型代码。这些代码工作量大、单调枯燥、占用大量开发时间。为了解决这个问题,出现了ORM思想。 **ORM(对象-关系映射):完成对象数据到关系型数据映射的机制称为对象-关系映射。** ## 二、MyBatis开发流程 详见[Java各种程序或框架创建流程](https://soki.me/archives/278.html)中的`二、MyBatis应用` ## 三、代码编写 #### 1、创建Maven项目 新建项目 -> Maven Archetype -> 填写项目名称(Day20) -> 选择`maven-archetype-quickstart` -> 创建  #### 2、配置仓库 编辑`pom.xml`文件,在``标签下添加JDK版本信息 ```xml 22 22 ``` 在``中添加MyBatis依赖 ```xml org.mybatis mybatis 3.5.19 com.mysql mysql-connector-j 9.4.0 ``` 点击右上角按钮解析`pom.xml`并重构项目依赖  #### 3、配置MyBatis 在`rescources`资源目录下创建`db.properties` ```properties jdbc.mysql.driver=com.mysql.cj.jdbc.Driver jdbc.mysql.url=jdbc:mysql://[address]:3306/[database]?useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8 jdbc.mysql.username=[username] jdbc.mysql.password=[password] ``` 创建`sqlMapperConfig.xml` ```xml ``` #### 4、添加数据库到IDEA(可选) 点开右侧数据库图标 选择`MySQL` 填写MySQL信息应用即可 #### 5、创建模型包 在项目根目录下创建`cn.doooog.mybatis.po`包,用来存放数据库表的实例对象类,此处创建`Emp.java` ```java package cn.doooog.mybatis.po; public class Emp { private Integer EMPno; private String ename; private String job; private Integer mgr; private String hiredate; private Double sal; private Double comm; private Integer DEPTno; public Emp() { } public Emp(Integer EMPno, String ename, String job, Integer mgr, String hiredate, Double sal, Double comm, Integer DEPTno) { this.EMPno = EMPno; this.ename = ename; this.job = job; this.mgr = mgr; this.hiredate = hiredate; this.sal = sal; this.comm = comm; this.DEPTno = DEPTno; } public Integer getDEPTno() { return DEPTno; } public void setDEPTno(Integer DEPTno) { this.DEPTno = DEPTno; } public Double getComm() { return comm; } public void setComm(Double comm) { this.comm = comm; } public Double getSal() { return sal; } public void setSal(Double sal) { this.sal = sal; } public String getHiredate() { return hiredate; } public void setHiredate(String hiredate) { this.hiredate = hiredate; } public Integer getMgr() { return mgr; } public void setMgr(Integer mgr) { this.mgr = mgr; } public String getJob() { return job; } public void setJob(String job) { this.job = job; } public String getEname() { return ename; } public void setEname(String ename) { this.ename = ename; } public Integer getEMPno() { return EMPno; } public void setEMPno(Integer EMPno) { this.EMPno = EMPno; } @Override public String toString() { return "Emp{" + "EMPno=" + EMPno + ", ename='" + ename + '\'' + ", job='" + job + '\'' + ", mgr='" + mgr + '\'' + ", hiredate='" + hiredate + '\'' + ", sal=" + sal + ", comm=" + comm + ", DEPTno=" + DEPTno + '}'; } } ``` #### 6、创建映射文件 在`rescources`目录下新建目录`cn/doooog/mybatis/po`目录,创建`Emp.xml` ```xml ``` 填写`SQL语句` ```xml select * from EMP ``` 在`SqlMapperConfig.xml`文件中``标签下添加映射 ```xml ``` #### 7、创建测试类 在项目根目录下创建`Test.java`文件 ```java package cn.doooog.mybatis; import cn.doooog.mybatis.po.Emp; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; import java.util.List; public class Test { public static void main(String[] args) { try { InputStream input = Resources.getResourceAsStream("sqlMapperConfig.xml"); SqlSession sqlSession = new SqlSessionFactoryBuilder().build(input).openSession(); List list = sqlSession.selectList("cn.doooog.mybatis.mapper.EmpMapper.listEmpAll"); System.out.println(list); sqlSession.close(); } catch (IOException e) { throw new RuntimeException(e); } } } ``` **注意**:`selectList()`用于执行一个无参数的列表查询;`selectOne()`用于执行一个无参数的单项查询;`selectMap(namespace.id,key)`可以添加key字段。 ## 四、有参查询 #### 1、添加SQL语句 在`EmpMapper.xml`文件中添加 ```xml select * from EMP where EMPno=#{EMPno} ``` #### 2、测试调用 在`Test.java`中添加 ```java Emp emp = sqlSession.selectOne("cn.doooog.mybatis.mapper.EmpMapper.getEmpById", 7788); System.out.println(emp); ``` ## 五、Mapper接口 采用MyBatis的代理开发方式实现DAO层的开发。 #### 1、开发规范 * 映射文件中的 namespace 必须是 mapper 接口的地址。 * 映射文件中 statement 的 id 必须与 mapper 接口中的方法名一致。 * 映射文件中 parameterType 必须与 mapper 接口中的方法参数类型一致。 * 映射文件中 resultType 必须与 mapper 接口中的返回值类型一致。(实际上,代理对象就是根据返回值类型来判断是使用selectOne方法还是selectList方法) #### 2、创建EmpMapper接口 在项目根目录下新建`cn.doooog.mybatis.mapper`包,创建`EmpMapper.java` ```java package cn.doooog.mybatis.mapper; import cn.doooog.mybatis.po.Emp; import java.util.List; public interface EmpMapper { List listEmpAll(); Emp getEmpById(Integer EMPno); } ``` ##### 测试调用 ```java package cn.doooog.mybatis; import cn.doooog.mybatis.mapper.EmpMapper; import cn.doooog.mybatis.po.Emp; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; import java.util.List; public class Test { public static void main(String[] args) { try { InputStream input = Resources.getResourceAsStream("sqlMapperConfig.xml"); SqlSession sqlSession = new SqlSessionFactoryBuilder().build(input).openSession(); EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class); List list = empMapper.listEmpAll(); Emp emp = empMapper.getEmpById(7788); System.out.println(emp); System.out.println(list); sqlSession.close(); } catch (IOException e) { throw new RuntimeException(e); } } } ``` **注意**:与之前不同的是,这次直接用创建的`*Mapper`接口来调用方法,通过`sqlSession.getMapper()`方法来让MyBatis代理实现接口。 #### 3、通过包来引入Mapper ```xml ``` **注意**:此处必须保证资源目录的路径与`mapper`包路径**完全相同**!!! #### 4、创建DeptMapper接口 在`po`包中创建`Dept.java` ```java package cn.doooog.mybatis.po; import java.util.List; public class Dept{ private Integer DEPTno; private String dname; private String loc; private List empList; public Dept() { } public Dept(Integer DEPTno, String dname, String loc, List empList) { this.DEPTno = DEPTno; this.dname = dname; this.loc = loc; this.empList = empList; } public List getEmpList() { return empList; } public void setEmpList(List empList) { this.empList = empList; } public Integer getDEPTno() { return DEPTno; } public void setDEPTno(Integer DEPTno) { this.DEPTno = DEPTno; } public String getDname() { return dname; } public void setDname(String dname) { this.dname = dname; } public String getLoc() { return loc; } public void setLoc(String loc) { this.loc = loc; } @Override public String toString() { return "Dept{" + "DEPTno=" + DEPTno + ", dname='" + dname + '\'' + ", loc='" + loc + '\'' + (empList != null && !empList.isEmpty() ? ", empList=" + empList : "") + '}'; } } ``` 在`mapper`包中创建`DeptMapper.java` ```java package cn.doooog.mybatis.mapper; import cn.doooog.mybatis.po.Dept; import java.util.List; public interface DeptMapper { List listDeptAll(); Dept getDeptById(Integer DEPTno); } ``` ##### 测试调用 ```java DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class); List list1 = deptMapper.listDeptAll(); System.out.println(list1); Dept dept = deptMapper.getDeptById(10); System.out.println(dept); ``` ## 六、定义类别名 类别名可以让`Mapper.xml`文件中自定义实例对象的类型不用写全包名,只需要写类名即可。 #### 1、添加别名标签 修改`sqlMapperConfig.xml`,在``标签后``标签前。 ```xml ``` #### 2、修改Mapper映射文件里的数据类型 `cn.doooog.mybatis.po.Emp` -> `Emp` `cn.doooog.mybatis.po.Dept` -> `Dept` Loading... # 数据库强化 ## 四、触发器 #### 1、触发器语法 ##### 创建触发器 ```sql CREATE TRIGGER 触发器名 触发时机 触发事件 ON 表 FOR EACH ROW BEGIN -- SQL代码 END; ``` 触发事件:`insert`、`update`、`delete` 触发时机:`before`、`after` `FOR EACH ROW`:对于其中的每个数据行,只要符合触发条件,就激活一次(行级触发器)。 ##### 删除触发器 ```sql DROP TRIGGER 触发器名; ``` ##### 查看触发器 ```sql SHOW TRIGGERS; ``` #### 2、触发器示例 ##### 触发器实现主表与外键表联级删除 ```sql CREATE TRIGGER dept_del BEFORE DELETE ON DEPT FOR EACH ROW BEGIN DELETE FROM EMP WHERE EMP.DEPTno = OLD.DEPTno; END; DELETE FROM DEPT WHERE DEPT.DEPTno=1; ``` **注意**:此处用来判断的要删除表需要用`OLD`来代替,不能直接写表名。、 ## 五、数据库优化 #### 1、适度的违反范式 在开发应用程序时,数据库设计要最大程度的遵守三范式。当 然,三范式最大的问题在于查询时通常需要join很多表,导致查询效率很低。所以有时候基于性能考虑,我们需要有意的违反三范式。也就是适度的做冗余,以达到提高查询效率的目的。注意这里的反范式是适度的。 #### 2、适当建立索引 索引可以有效的提高查询速度,但这个提高是以插入、更新、删除的速度为代价的。由于索引的存储结构不同于表的存储,一个表的索引所占空间比可能数据所占空间还大。这意味着我们在写数据库的时候做了很多额外的工作,而这个工作只是为了提高读的效率。因此,我们建立一个索引,必须保证这个索引不会“亏本”。一般需要遵守这样的规则: * 对经常更新的表就避免对其进行过多的索引。 * 对经常用于查询的字段应该创建索引。 * 数据量小的表最好不要使用索引。 * 相同值较多的字段上不要建立索引(比如"性别"字段)。相反的,在不同值较多的字段上可以建立索引。 #### 3、对表进行水平划分 如果一个表的记录数太多了,比如上千万条,而且需要经常检索,那么我们就有必要化整为零了。如果我拆成100个表,那么每个表只有10万条记录。当然这 需要数据在逻辑上可以划分。一个好的划分依据,有利于程序的简单实现,也可以充分利用水平分表的优势。 比如系统界面上只提供按月查询的功能,那么把表按月拆分成12个,每个查询只查询一个表就够了。 #### 4、对表进行垂直划分 有些表记录数并不多,但是字段却很多,导致表占用空间很大,检索表时需要执行大量I/O,严重降低了性能。解决方案是:可以把一部分字段拆分到另一个表,并且该表与原表是一对一的关系。 #### 5、选择合适的引擎 在Oracle和SQL Server等数据库中只有一种存储引擎,所有数据存储管理机制都是一样的。而MySQL数据库提供了多种存储引擎,用户可以根据不同的需求为数据表选择不同的存储引擎。比如: * InnoDB存储引擎支持外键、支持事务、支持全文检索; * MyISAM存储引擎可以被压缩、不支持事务、不支持外键;如果需要执行大量的select语句,MyISAM存储引擎是更好的选择。 * MEMORY存储引擎主要用于那些内容稳定的表,或者作为统计操作的中间表。 ## 六、SQL语句优化 #### 1、尽量使用批量操作 尽量使用MySql中的批量操作语句,这样可以避免频繁读写操作。比如:批量插入、批量更新、批量删除。 ```sql /* 使用多个insert语句效率低 */ insert into dept values(null,'技术部','沈阳市'); insert into dept values(null,'销售部','上海市'); insert into dept values(null,'总部','北京市'); /* 使用批量insert语句效率高 */ insert into dept values(null,'技术部','沈阳市'),(null,'销售部','上海市'),(null,'总部','北京市'); ``` #### 2、选择适当的数据类型 选择字段的数据类型的一般原则是尽量使用占用字节小的数据类型。 比如主键, 强烈建议用自增类型,既节省空间,又能满足大多数需求。 #### 3、文件、图片等大文件用文件系统存储,不要使用数据库 数据库只存储文件路径。这是一个基本原则! #### 4、使用连接(JOIN)来代替子查询(Sub-Queries) MySQL从4.1开始支持SQL的子查询。但是,子查询可以被更有效率的连接替代。连接之所以更有效率一些,是因为MySQL不需要在内存中创建临时表来完成需要多个步骤才能完成的子查询。 ```sql /* 查询部门地址在"NEW YORK"的所有员工 */ /* 子查询方式效率低 */ select * from emp where deptno in(select deptno from dept where loc='NEW YORK') /* 多表连接方式效率高 */ select e.* from emp e,dept d where e.deptno=d.deptno and d.loc='NEW YORK' ``` #### 5、对查询语句进行优化 绝大多数情况下,使用索引可以提高查询的速度,但如果SQL语句使用不恰当的话,索引将无法发挥它应有的作用。下面是应该注意的几个方面。 * 首先,最好是在相同类型的字段间进行比较的操作,可以避免转型的步骤。 * 其次,在建有索引的字段上尽量不要使用函数进行操作。使用函数后索引将失效。 * 在搜索字符型字段时,我们有时会使用LIKE关键字和通配符,这种做法虽然简单,但却也是以牺牲系统性能为代价的。 * 应该注意避免在查询中让MySQL进行自动类型转换,因为转换过程也会使索引变得不起作用。 ## 七、数据库参数配置优化 MySql安装之后,默认参数并不能满足所有生产场合下的需求。所以,还需要根据需求,修改Mysql服务器的系统参数,达到合理利用服务器现有资源,最大合理的提高MySQL性能。比如: * wait_timeout:MySQL客户端的数据库连接闲置最大时间值。 * max_connections:MySQL的最大连接数。 * max_user_connections:每个数据库用户的最大连接。 * thread_concurrency:线程最大并发数。 * default-storage-engine:设置MySQL默认存储引擎 ```sql -- 查询MySQL的最大连接数。 show global variables like '%max_connections%'; -- 设置MySQL的最大连接数。 set global max_connections=1024; ``` ## 八、硬件和系统的优化 #### 1、合理采用操作系统 如果服务器内存超过4G,那么毋庸置疑应当采用64位操作系统和64位mysql #### 2、读写分离 如果数据库压力很大,一台机器支撑不了,那么可以用mysql复制实现多台机器同步,将数据库的压力分散。 比如:主库用来写入,从库都用来做select,那么每个数据库分担的压力小了很多。当然,要实现这种方式,需要程序特别设计,给程序开发带来了额外负担。不过现在已经有中间件来实现这些功能。 --- # Maven ## 一、Maven安装与配置 具体内容见[MyBatis框架基础](https://soki.me/archives/237.html)的第一条。 --- # MyBatis 此处知识点与[MyBatis框架基础](https://www.soki.me/archives/237.html)内容高度重复,只是用来记录上课流程,更加详细的内容请参考前面文章。 ## 一、ORM思想 数据库中数据是以表的形式存在的,而java中使用的数据都是对象型的。所以不得不要将表数据转换成对象数据。 这样就会产生大量的没有技术含量的纯 “体力” 型代码。 ```java while(rs.next()) { Business business = new Business(); business.setBusinessId(rs.getInt("businessId")); business.setPassword(rs.getString("password")); business.setBusinessName(rs.getString("businessName")); business.setBusinessAddress(rs.getString("businessAddress")); business.setBusinessExplain(rs.getString("businessExplain")); business.setStarPrice(rs.getDouble("starPrice")); business.setDeliveryPrice(rs.getDouble("deliveryPrice")); list.add(business); } ``` 上面代码就属于纯 “体力” 型代码。这些代码工作量大、单调枯燥、占用大量开发时间。为了解决这个问题,出现了ORM思想。 **ORM(对象-关系映射):完成对象数据到关系型数据映射的机制称为对象-关系映射。** ## 二、MyBatis开发流程 详见[Java各种程序或框架创建流程](https://soki.me/archives/278.html)中的`二、MyBatis应用` ## 三、代码编写 #### 1、创建Maven项目 新建项目 -> Maven Archetype -> 填写项目名称(Day20) -> 选择`maven-archetype-quickstart` -> 创建  #### 2、配置仓库 编辑`pom.xml`文件,在`<properties>`标签下添加JDK版本信息 ```xml <maven.compiler.source>22</maven.compiler.source> <maven.compiler.target>22</maven.compiler.target> ``` 在`<dependencies>`中添加MyBatis依赖 ```xml <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.19</version> </dependency> <!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <version>9.4.0</version> </dependency> ``` 点击右上角按钮解析`pom.xml`并重构项目依赖  #### 3、配置MyBatis 在`rescources`资源目录下创建`db.properties` ```properties jdbc.mysql.driver=com.mysql.cj.jdbc.Driver jdbc.mysql.url=jdbc:mysql://[address]:3306/[database]?useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8 jdbc.mysql.username=[username] jdbc.mysql.password=[password] ``` 创建`sqlMapperConfig.xml` ```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> <!-- 加载其他配置文件 --> <properties resource="db.properties"/> <!-- 配置数据源 --> <environments default="development"> <environment id="development"> <!-- 数据源的事务管理 --> <transactionManager type="JDBC"/> <!-- 配置JDBC数据库信息 --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.mysql.driver}"/> <property name="url" value="${jdbc.mysql.url}"/> <property name="username" value="${jdbc.mysql.username}"/> <property name="password" value="${jdbc.mysql.password}"/> </dataSource> </environment> </environments> <!-- 配置映射文件 --> <mappers> </mappers> </configuration> ``` #### 4、添加数据库到IDEA(可选) 点开右侧数据库图标 <img src="https://pic.soki.me/file/piclist/image-20251024142730649.png" alt="image-20251024142730649" style="zoom:50%;" style=""> 选择`MySQL` <img src="https://pic.soki.me/file/piclist/image-20251024143310429.png" alt="image-20251024143310429" style="zoom:50%;" style=""> 填写MySQL信息应用即可 <img src="https://pic.soki.me/file/piclist/image-20251024143632764.png" alt="image-20251024143632764" style="zoom:50%;" style=""> #### 5、创建模型包 在项目根目录下创建`cn.doooog.mybatis.po`包,用来存放数据库表的实例对象类,此处创建`Emp.java` ```java package cn.doooog.mybatis.po; public class Emp { private Integer EMPno; private String ename; private String job; private Integer mgr; private String hiredate; private Double sal; private Double comm; private Integer DEPTno; public Emp() { } public Emp(Integer EMPno, String ename, String job, Integer mgr, String hiredate, Double sal, Double comm, Integer DEPTno) { this.EMPno = EMPno; this.ename = ename; this.job = job; this.mgr = mgr; this.hiredate = hiredate; this.sal = sal; this.comm = comm; this.DEPTno = DEPTno; } public Integer getDEPTno() { return DEPTno; } public void setDEPTno(Integer DEPTno) { this.DEPTno = DEPTno; } public Double getComm() { return comm; } public void setComm(Double comm) { this.comm = comm; } public Double getSal() { return sal; } public void setSal(Double sal) { this.sal = sal; } public String getHiredate() { return hiredate; } public void setHiredate(String hiredate) { this.hiredate = hiredate; } public Integer getMgr() { return mgr; } public void setMgr(Integer mgr) { this.mgr = mgr; } public String getJob() { return job; } public void setJob(String job) { this.job = job; } public String getEname() { return ename; } public void setEname(String ename) { this.ename = ename; } public Integer getEMPno() { return EMPno; } public void setEMPno(Integer EMPno) { this.EMPno = EMPno; } @Override public String toString() { return "Emp{" + "EMPno=" + EMPno + ", ename='" + ename + '\'' + ", job='" + job + '\'' + ", mgr='" + mgr + '\'' + ", hiredate='" + hiredate + '\'' + ", sal=" + sal + ", comm=" + comm + ", DEPTno=" + DEPTno + '}'; } } ``` #### 6、创建映射文件 在`rescources`目录下新建目录`cn/doooog/mybatis/po`目录,创建`Emp.xml` ```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:命名空间 访问时:命名空间.语句id标识--> <mapper namespace="cn.doooog.mybatis.mapper.EmpMapper"> </mapper> ``` 填写`SQL语句` ```xml <select id="listEmpAll"> select * from EMP </select> ``` 在`SqlMapperConfig.xml`文件中`<mappers>`标签下添加映射 ```xml <mapper url="cn/doooog/mybatis/mapper/EmpMapper.xml"/> ``` #### 7、创建测试类 在项目根目录下创建`Test.java`文件 ```java package cn.doooog.mybatis; import cn.doooog.mybatis.po.Emp; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; import java.util.List; public class Test { public static void main(String[] args) { try { InputStream input = Resources.getResourceAsStream("sqlMapperConfig.xml"); SqlSession sqlSession = new SqlSessionFactoryBuilder().build(input).openSession(); List<Emp> list = sqlSession.selectList("cn.doooog.mybatis.mapper.EmpMapper.listEmpAll"); System.out.println(list); sqlSession.close(); } catch (IOException e) { throw new RuntimeException(e); } } } ``` **注意**:`selectList()`用于执行一个无参数的列表查询;`selectOne()`用于执行一个无参数的单项查询;`selectMap(namespace.id,key)`可以添加key字段。 ## 四、有参查询 #### 1、添加SQL语句 在`EmpMapper.xml`文件中添加 ```xml <select id="getEmpById" resultType="cn.doooog.mybatis.po.Emp" parameterType="Integer"> select * from EMP where EMPno=#{EMPno} </select> ``` #### 2、测试调用 在`Test.java`中添加 ```java Emp emp = sqlSession.selectOne("cn.doooog.mybatis.mapper.EmpMapper.getEmpById", 7788); System.out.println(emp); ``` ## 五、Mapper接口 采用MyBatis的代理开发方式实现DAO层的开发。 #### 1、开发规范 * 映射文件中的 namespace 必须是 mapper 接口的地址。 * 映射文件中 statement 的 id 必须与 mapper 接口中的方法名一致。 * 映射文件中 parameterType 必须与 mapper 接口中的方法参数类型一致。 * 映射文件中 resultType 必须与 mapper 接口中的返回值类型一致。(实际上,代理对象就是根据返回值类型来判断是使用selectOne方法还是selectList方法) #### 2、创建EmpMapper接口 在项目根目录下新建`cn.doooog.mybatis.mapper`包,创建`EmpMapper.java` ```java package cn.doooog.mybatis.mapper; import cn.doooog.mybatis.po.Emp; import java.util.List; public interface EmpMapper { List<Emp> listEmpAll(); Emp getEmpById(Integer EMPno); } ``` ##### 测试调用 ```java package cn.doooog.mybatis; import cn.doooog.mybatis.mapper.EmpMapper; import cn.doooog.mybatis.po.Emp; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; import java.util.List; public class Test { public static void main(String[] args) { try { InputStream input = Resources.getResourceAsStream("sqlMapperConfig.xml"); SqlSession sqlSession = new SqlSessionFactoryBuilder().build(input).openSession(); EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class); List<Emp> list = empMapper.listEmpAll(); Emp emp = empMapper.getEmpById(7788); System.out.println(emp); System.out.println(list); sqlSession.close(); } catch (IOException e) { throw new RuntimeException(e); } } } ``` **注意**:与之前不同的是,这次直接用创建的`*Mapper`接口来调用方法,通过`sqlSession.getMapper()`方法来让MyBatis代理实现接口。 #### 3、通过包来引入Mapper ```xml <!-- 配置映射文件 --> <mappers> <package name="cn.doooog.mybatis.mapper"/> </mappers> ``` **注意**:此处必须保证资源目录的路径与`mapper`包路径**完全相同**!!! #### 4、创建DeptMapper接口 在`po`包中创建`Dept.java` ```java package cn.doooog.mybatis.po; import java.util.List; public class Dept{ private Integer DEPTno; private String dname; private String loc; private List<Emp> empList; public Dept() { } public Dept(Integer DEPTno, String dname, String loc, List<Emp> empList) { this.DEPTno = DEPTno; this.dname = dname; this.loc = loc; this.empList = empList; } public List<Emp> getEmpList() { return empList; } public void setEmpList(List<Emp> empList) { this.empList = empList; } public Integer getDEPTno() { return DEPTno; } public void setDEPTno(Integer DEPTno) { this.DEPTno = DEPTno; } public String getDname() { return dname; } public void setDname(String dname) { this.dname = dname; } public String getLoc() { return loc; } public void setLoc(String loc) { this.loc = loc; } @Override public String toString() { return "Dept{" + "DEPTno=" + DEPTno + ", dname='" + dname + '\'' + ", loc='" + loc + '\'' + (empList != null && !empList.isEmpty() ? ", empList=" + empList : "") + '}'; } } ``` 在`mapper`包中创建`DeptMapper.java` ```java package cn.doooog.mybatis.mapper; import cn.doooog.mybatis.po.Dept; import java.util.List; public interface DeptMapper { List<Dept> listDeptAll(); Dept getDeptById(Integer DEPTno); } ``` ##### 测试调用 ```java DeptMapper deptMapper = sqlSession.getMapper(DeptMapper.class); List<Dept> list1 = deptMapper.listDeptAll(); System.out.println(list1); Dept dept = deptMapper.getDeptById(10); System.out.println(dept); ``` ## 六、定义类别名 类别名可以让`Mapper.xml`文件中自定义实例对象的类型不用写全包名,只需要写类名即可。 #### 1、添加别名标签 修改`sqlMapperConfig.xml`,在`<properties>`标签后`<environments>`标签前。 ```xml <!-- 添加类别名 --> <typeAliases> <package name="cn.doooog.mybatis.po"/> </typeAliases> ``` #### 2、修改Mapper映射文件里的数据类型 `cn.doooog.mybatis.po.Emp` -> `Emp` `cn.doooog.mybatis.po.Dept` -> `Dept` 最后修改:2025 年 10 月 26 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 👆请简单粗暴地爱我。