在实际开发中,工程中本质的任务是从数据库中获取数据,而后对数据进行操做,又或者写入数据.开发时语言是大可能是面向对象的工程语言,这个时候就必须进行工程语言和数据库链接语言的转换,也就是所谓的ORM对象关系映射.html
那么须要使用到链接数据库的技术,如Java的JDBC,或者其余语言的ODBC等.然而,这种技术虽然能很好地与数据库进行互动,可是有个问题是每一次访问动做都必须保证链接时间较短(避免占用资源),本身进行链接的开闭,SQL语句的拼写.....java
实在是太繁琐了,严重影响工程开发进度以及编码者的心情,尤为是第二点,形成很恶劣的影响.因此,有人就编写出了ORM框架来帮你进行两种语言半自动转换,代价是你须要写一些配置文件.mysql
ORM框架基本思想类似:git
1.从配置文件中获得sessionFactory;github
2.由sessionFactory产生session;redis
3.在session中完成CRUD和事务提交等操做;spring
4.关闭session;sql
Mybatis是什么?数据库
mybatis是一个持久层框架,apache基金会热门项目之一.apache
Mybatis是java这种工程语言用到的一种ORM框架,它能作的事本质上就是帮你处理两种语言之间的转换.
mybatis能够将向prepareStatement中的输入参数自动进行输入映射,将查询结果灵活映射成java对象(输出映射).
充当以前jdbc链接的持久层(dao)的功能.
1.建立数据库
/* SQLyog v10.2 MySQL - 5.1.72-community : Database - mybatis ********************************************************************* */ /*!40101 SET NAMES utf8 */; /*!40101 SET SQL_MODE=''*/; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; /*Table structure for table `items` */ CREATE TABLE `items` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(32) NOT NULL COMMENT '商品名称', `price` float(10,1) NOT NULL COMMENT '商品订价', `detail` text COMMENT '商品描述', `pic` varchar(64) DEFAULT NULL COMMENT '商品图片', `createtime` datetime NOT NULL COMMENT '生产日期', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; /*Table structure for table `orderdetail` */ CREATE TABLE `orderdetail` ( `id` int(11) NOT NULL AUTO_INCREMENT, `orders_id` int(11) NOT NULL COMMENT '订单id', `items_id` int(11) NOT NULL COMMENT '商品id', `items_num` int(11) DEFAULT NULL COMMENT '商品购买数量', PRIMARY KEY (`id`), KEY `FK_orderdetail_1` (`orders_id`), KEY `FK_orderdetail_2` (`items_id`), CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; /*Table structure for table `orders` */ CREATE TABLE `orders` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL COMMENT '下单用户id', `number` varchar(32) NOT NULL COMMENT '订单号', `createtime` datetime NOT NULL COMMENT '建立订单时间', `note` varchar(100) DEFAULT NULL COMMENT '备注', PRIMARY KEY (`id`), KEY `FK_orders_1` (`user_id`), CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; /*Table structure for table `user` */ CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(32) NOT NULL COMMENT '用户名称', `birthday` date DEFAULT NULL COMMENT '生日', `sex` char(1) DEFAULT NULL COMMENT '性别', `address` varchar(256) DEFAULT NULL COMMENT '地址', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /* SQLyog v10.2 MySQL - 5.1.72-community : Database - mybatis ********************************************************************* */ /*!40101 SET NAMES utf8 */; /*!40101 SET SQL_MODE=''*/; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; /*Data for the table `items` */ insert into `items`(`id`,`name`,`price`,`detail`,`pic`,`createtime`) values (1,'台式机',3000.0,'该电脑质量很是好!!!!',NULL,'2015-02-03 13:22:53'),(2,'笔记本',6000.0,'笔记本性能好,质量好!!!!!',NULL,'2015-02-09 13:22:57'),(3,'背包',200.0,'名牌背包,容量大质量好!!!!',NULL,'2015-02-06 13:23:02'); /*Data for the table `orderdetail` */ insert into `orderdetail`(`id`,`orders_id`,`items_id`,`items_num`) values (1,3,1,1),(2,3,2,3),(3,4,3,4),(4,4,2,3); /*Data for the table `orders` */ insert into `orders`(`id`,`user_id`,`number`,`createtime`,`note`) values (3,1,'1000010','2015-02-04 13:22:35',NULL),(4,1,'1000011','2015-02-03 13:22:41',NULL),(5,10,'1000012','2015-02-12 16:13:23',NULL); /*Data for the table `user` */ insert into `user`(`id`,`username`,`birthday`,`sex`,`address`) values (1,'王五',NULL,'2',NULL),(10,'张三','2014-07-10','1','北京市'),(16,'张小明',NULL,'1','河南郑州'),(22,'陈小明',NULL,'1','河南郑州'),(24,'张三丰',NULL,'1','河南郑州'),(25,'陈小明',NULL,'1','河南郑州'),(26,'王五',NULL,NULL,NULL); /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
2.建立maven工程,pox.xml下引入mybatis,log4j,mysql,junit等依赖.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/jdbc/spring-cache.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.harry</groupId> <artifactId>harry-mybatis</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>harry-mybatis Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.1</version> </dependency> <!-- https://mvnrepository.com/artifact/log4j/log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-core --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.11.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.3.11.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.40</version> </dependency> </dependencies> <build> <finalName>harry-mybatis</finalName> </build> </project>
3.在resource中配置log4j.properties;
# Global logging configuration log4j.rootLogger=DEBUG, stdout # Console output... log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
4.建立User.java(POJO)
package com.harry.entity; import java.io.Serializable; import java.util.Date; import java.util.List; @SuppressWarnings("serial") public class User implements Serializable { //属性名和数据库表的字段对应 private int id; private String username;// 用户姓名 private String sex;// 性别 private Date birthday;// 生日 private String address;// 地址 //用户建立的订单列表 private List<Orders> ordersList; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address=" + address + "]"; } public List<Orders> getOrdersList() { return ordersList; } public void setOrdersList(List<Orders> ordersList) { this.ordersList = ordersList; } }
5.建立IDAO,IUserDAO继承IDAO,UserDAOImpl实现IUSerDAO(数据库链接开关应在service层)
偷懒,此处参考软件开发 : 软件分层设计.
这里在mybatis中用以UserMapper.java和UserMapper.xml替代
6.进行链接增删改查测试.
Mybatis使用Mapper来取代DAO,其实二者做用是相同的,就是用来操做POJO.
7. 建立UserMapper接口和UserMapper.xml(用户输入参数)
package com.harry.mapper; import com.harry.entity.User; public interface UserMapper { //根据id查询用户信息 public User findUserById(int id) throws Exception; //根据用户名列查询用户列表 public List<User> findUserByName(String name)throws Exception; //插入用户 public void doInsertUser(User user)throws Exception; //删除用户 public void doDeleteUser(int id)throws Exception; //更新用户 public void doUpdateUser(int id)throw Exception); }
<?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.harry.mapper.UserMapper"> <select id="findUserById" parameterType="int" resultType="com.harry.entity.User"> SELECT * FROM USER WHERE id=#{value} </select> <select id="findUserByName" parameterType="java.lang.String" resultType="com.harry.entity.User"> SELECT * FROM user WHERE username LIKE '%${value}%' </select> <insert id="insertUser" parameterType="com.harry,entiyUser"> <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String"> SELECT uuid() </selectKey> INSERT INTO user(id,username,birthday,sex,address) VALUE(#{id},#{username},#{birthday},#{sex},#{address}) </insert> <delete id="deleteUser" parameterType="java.lang.Integer"> DELETE FROM user WHERE id=#{id} </delete> <update id="updateUser" parameterType="java.lang.Integer"> UPDATE user SET username = "Harry" WHERE id = #{id} </update> </mapper>
8.引入mybatis配置文件
<?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"> <!--properties中还能够配置一些属性名和属性值 --> <!-- <property name="jdbc.driver" value=""/> --> </properties> <!-- 全局配置参数,须要时再设置 --> <!-- <settings> </settings> --> <!-- 别名定义 --> <typeAliases> <package name="com.harry.entity"/> </typeAliases> <!-- 和spring整合后 environments配置将废除--> <environments default="development"> <environment id="development"> <!-- 使用jdbc事务管理,事务控制由mybatis--> <transactionManager type="JDBC" /> <!-- 数据库链接池,由mybatis管理--> <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> <!-- 加载 映射文件 --> <mappers> <package name="com.harry.mapper"/> </mappers> </configuration>
注意:配置中目录结构以下和运行结果以下:
1.用户编写sqlMapConfig.xml全局配置文件
2.建立POJO
3.建立获取sqlSession
4.建立Mapper接口与Mapper.xml配置文件
5.定义SQL传入参数
6.使用Mapper接口
1.数据库链接建立、释放形成系统资源浪费从而影响系统性能,若是使用链接池可解决这个问题.
解决:在SqlMapConfig.xml中配置数据链接池,使用链接池管理数据库连接.
2.Sql语句硬编码在代码中形成代码,sql一改变程序及必须从新编译,实际应用sql变化的可能较大,sql变更须要改变java代码.
解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离.
3.向sql语句传参数麻烦,由于sql语句的where条件不必定,可能多也可能少,占位符须要和参数一一对应.
解决:Mybatis自动将java对象映射至sql语句,经过statement中的parameterType定义输入参数的类型.
4.对结果集解析麻烦,sql变化致使解析代码变化,且解析前须要遍历,若是能将数据库记录封装成pojo对象解析比较方便.
解决:Mybatis自动将sql执行结果映射至java对象,经过statement中的resultType定义输出结果的类型.
在实际开发中,咱们能够编写一个MybatisUtil辅助类来进行对进行操做,不过当有链接池和Spring对象注入,这个工具类就没有必要.
1)在静态初始化块中加载mybatis配置文件和StudentMapper.xml文件一次
2)使用ThreadLocal对象让当前线程与SqlSession对象绑定在一块儿
3)获取当前线程中的SqlSession对象,若是没有的话,从SqlSessionFactory对象中获取SqlSession对象
4)获取当前线程中的SqlSession对象,再将其关闭,释放其占用的资源
/** * MyBatis工具类 * @author AdminTC */ public class MyBatisUtil { private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>(); private static SqlSessionFactory sqlSessionFactory; static{ try { Reader reader = Resources.getResourceAsReader("mybatis.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } private MyBatisUtil(){} public static SqlSession getSqlSession(){ SqlSession sqlSession = threadLocal.get(); if(sqlSession == null){ sqlSession = sqlSessionFactory.openSession(); threadLocal.set(sqlSession); } return sqlSession; } public static void closeSqlSession(){ SqlSession sqlSession = threadLocal.get(); if(sqlSession != null){ sqlSession.close(); threadLocal.remove(); } } public static void main(String[] args) { Connection conn = MyBatisUtil.getSqlSession().getConnection(); System.out.println(conn!=null?"链接成功":"链接失败"); } }
什么是动态sql?当查询参数数量未知,须要靠查询者动态地添加查询条件.
知识点:
1.当遇到跨表查询的时候,你用什么对象来承接对象?是否是须要一个表数据结合体对象来进行承接?
2.对查询条件进行判断,若是输入参数不为空才进行查询条件拼接.
3.使用<where>替代WHERE.
使用查询视图对象来包装跨表查询的状况,建立UserQueryVO.java
package com.harry.entity; import java.util.List; public class UserQueryVO { //传入多个id private List<Integer> ids; //在这里包装所须要的查询条件 //用户查询条件 private User user; public User getUser() { return user; } public void setUser(User user) { this.user = user; } public List<Integer> getIds() { return ids; } public void setIds(List<Integer> ids) { this.ids = ids; } //能够包装其它的查询条件,订单、商品 //.... }
<mapper namespace="com.harry.mapper.UserMapper"> <!-- 定义sql片断 id:sql片断的惟 一标识 经验:是基于单表来定义sql片断,这样话这个sql片断可重用性才高 在sql片断中不要包括 where --> <sql id="query_user_where"> <if test="user!=null"> <if test="user.sex!=null and user.sex!=''"> and user.sex = #{user.sex} </if> <if test="user.username!=null and user.username!=''"> and user.username LIKE '%${user.username}%' </if> <if test="ids!=null"> <!-- 使用 foreach遍历传入ids collection:指定输入 对象中集合属性 item:每一个遍历生成对象中 open:开始遍历时拼接的串 close:结束遍历时拼接的串 separator:遍历的两个对象中须要拼接的串 --> <!-- 使用实现下边的sql拼接: AND (id=1 OR id=10 OR id=16) --> <foreach collection="ids" item="user_id" open="AND (" close=")" separator="or"> <!-- 每一个遍历须要拼接的串 --> id=#{user_id} </foreach> <!-- 实现 “ and id IN(1,10,16)”拼接 --> <!-- <foreach collection="ids" item="user_id" open="and id IN(" close=")" separator=","> 每一个遍历须要拼接的串 #{user_id} </foreach> --> </if> </if> </sql> <select id="findUserList" parameterType="com.harry.entity.UserQueryVO" resultType="com.harry.entity.UserCustom"> SELECT * FROM USER <!-- where能够自动去掉条件中的第一个and --> <where> <!-- 引用sql片断 的id,若是refid指定的id不在本mapper文件中,须要前边加namespace --> <include refid="query_user_where"></include> <!-- 在这里还要引用其它的sql片断 --> </where>
sqlMapperConfig.xml
db.properties
将数据源链接信息存储在.properties文件中,避免将信息硬编码至java类中,这样即便修改了数据源信息也不用再次编译程序.
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=password
<?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"> <!-- 在properties内部用property定义属性 --> <!-- 若是外部配置文件有该属性,则内部定义属性被外部属性覆盖 --> </properties> <!-- 和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?characterEncoding=utf-8" /> <property name="username" value="root" /> <property name="password" value="bendanren" /> --> <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> <mappers> <mapper resource="sqlmap/User.xml"/> </mappers> </configuration>
typeAliases
批量进行别名扫描,自动定义别名,别名就是类名
<typeAliases> <package name="com.harry.mybatis"/> </typeAliases>
typeHandlers(类型处理器)
Mybatis中经过类型处理器完成对jdbc和java类型转换
typeHandlers,Mybatis提供的typeHandler能够知足大部分开发要求
Mappers(映射配置,在mybatis总配置文件中配置)
经过resource加载mapper文件 <mapper resource="sqlmap/UserMapper.xml"/>
经过class来加载mapper文件 <mapper class="com.harry.mybatis.UserMapper"/>
经过package批量加载mapper文件(推荐使用) <mapper package="com.harry.mybatis"/>
Mapper.xml
输入映射
经过parameterType指定输入参数的类型,类型能够是简单类型,hashmap,pojo的包装类型
输出映射
resultType(selectOne)
使用resultType进行输出映射,只有查询出来的列名和pojo的属性名一致,该列才能够映射成功.
若是查询出来的列名与pojo属性名全不一致,没有建立pojo对象.
resultMap(SelectList)
使用resultMap进行输出映射,对进行多个pojo进行映射.
高级映射
高级映射指的是表与表之间的关系映射(一对一,一对多,多对多),分析关系映射没有思路的话是很可贵出正确结果,因此下面讲述分析思路.
数据模型的分析思路
![]()
/* SQLyog v10.2 MySQL - 5.1.72-community : Database - mybatis ********************************************************************* */ /*!40101 SET NAMES utf8 */; /*!40101 SET SQL_MODE=''*/; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; /*Table structure for table `items` */ CREATE TABLE `items` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(32) NOT NULL COMMENT '商品名称', `price` float(10,1) NOT NULL COMMENT '商品订价', `detail` text COMMENT '商品描述', `pic` varchar(64) DEFAULT NULL COMMENT '商品图片', `createtime` datetime NOT NULL COMMENT '生产日期', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; /*Table structure for table `orderdetail` */ CREATE TABLE `orderdetail` ( `id` int(11) NOT NULL AUTO_INCREMENT, `orders_id` int(11) NOT NULL COMMENT '订单id', `items_id` int(11) NOT NULL COMMENT '商品id', `items_num` int(11) DEFAULT NULL COMMENT '商品购买数量', PRIMARY KEY (`id`), KEY `FK_orderdetail_1` (`orders_id`), KEY `FK_orderdetail_2` (`items_id`), CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; /*Table structure for table `orders` */ CREATE TABLE `orders` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL COMMENT '下单用户id', `number` varchar(32) NOT NULL COMMENT '订单号', `createtime` datetime NOT NULL COMMENT '建立订单时间', `note` varchar(100) DEFAULT NULL COMMENT '备注', PRIMARY KEY (`id`), KEY `FK_orders_1` (`user_id`), CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; /*Table structure for table `user` */ CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(32) NOT NULL COMMENT '用户名称', `birthday` date DEFAULT NULL COMMENT '生日', `sex` char(1) DEFAULT NULL COMMENT '性别', `address` varchar(256) DEFAULT NULL COMMENT '地址', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /* SQLyog v10.2 MySQL - 5.1.72-community : Database - mybatis ********************************************************************* */ /*!40101 SET NAMES utf8 */; /*!40101 SET SQL_MODE=''*/; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; /*Data for the table `items` */ insert into `items`(`id`,`name`,`price`,`detail`,`pic`,`createtime`) values (1,'台式机',3000.0,'该电脑质量很是好!!!!',NULL,'2015-02-03 13:22:53'),(2,'笔记本',6000.0,'笔记本性能好,质量好!!!!!',NULL,'2015-02-09 13:22:57'),(3,'背包',200.0,'名牌背包,容量大质量好!!!!',NULL,'2015-02-06 13:23:02'); /*Data for the table `orderdetail` */ insert into `orderdetail`(`id`,`orders_id`,`items_id`,`items_num`) values (1,3,1,1),(2,3,2,3),(3,4,3,4),(4,4,2,3); /*Data for the table `orders` */ insert into `orders`(`id`,`user_id`,`number`,`createtime`,`note`) values (3,1,'1000010','2015-02-04 13:22:35',NULL),(4,1,'1000011','2015-02-03 13:22:41',NULL),(5,10,'1000012','2015-02-12 16:13:23',NULL); /*Data for the table `user` */ insert into `user`(`id`,`username`,`birthday`,`sex`,`address`) values (1,'王五',NULL,'2',NULL),(10,'张三','2014-07-10','1','北京市'),(16,'张小明',NULL,'1','河南郑州'),(22,'陈小明',NULL,'1','河南郑州'),(24,'张三丰',NULL,'1','河南郑州'),(25,'陈小明',NULL,'1','河南郑州'),(26,'王五',NULL,NULL,NULL); /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
推导思路
- 用户表user:记录了购买商品的用户信息
- 订单表orders:记录了用户所建立的订单(购买商品的订单)
- 订单明细表orderdetail:记录了订单的详细信息即购买商品的信息
- 商品表items:记录了商品信息
表与表之间的业务关系:
在分析表与表之间的业务关系时须要创建在某个业务意义基础上去分析.先分析数据级别之间有关系的表之间的业务关系:
- usre和orders:
user—>orders:一个用户能够建立多个订单,一对多
orders—>user:一个订单只由一个用户建立,一对一
- orders和orderdetail:
orders—>orderdetail:一个订单能够包括多个订单明细,由于一个订单能够购买多个商品,每一个商品的购买信息在orderdetail记录,一对多关系
orderdetail—> orders:一个订单明细只能包括在一个订单中,一对一
- orderdetail和itesm:
orderdetail—>itesms:一个订单明细只对应一个商品信息,一对一
items—> orderdetail:一个商品能够包括在多个订单明细 ,一对多
再分析数据库级别没有关系的表之间是否有业务关系:
- orders和items:
orders和items之间能够经过orderdetail表创建关系.
需求1. 查询订单信息,关联查询建立订单的用户信息(一对一查询)
1.1. sql
肯定查询的主表: 订单表
得出SELECT * FROM orders
而后肯定关联表: 用户表
使用内链接仍是外链接?
因为orders表有一个外键(user_id),经过外键关联查询用户只能查出一条记录(由于是一对一的关系),可使用内连接.
SELECT * FROM orders.*,
user.username,
user.sex,
user.address
FROM orders,user
WHERE orders.user_id = user.id;
1.2 建立pojo
package com.harry.entity; import java.io.Serializable; import java.util.Date; import java.util.List; @SuppressWarnings("serial") public class User implements Serializable { //属性名和数据库表的字段对应 private int id; private String username;// 用户姓名 private String sex;// 性别 private Date birthday;// 生日 private String address;// 地址 //用户建立的订单列表 private List<Orders> ordersList; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", sex=" + sex + ", birthday=" + birthday + ", address=" + address + "]"; } public List<Orders> getOrdersList() { return ordersList; } public void setOrdersList(List<Orders> ordersList) { this.ordersList = ordersList; } }
package com.harry.entity; import java.util.Date; import java.util.List; public class Orders { private Integer id; private Integer userId; private String number; private Date createtime; private String note; //用户信息 private User user; //订单明细 private List<Orderdetail> orderdetails; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number == null ? null : number.trim(); } public Date getCreatetime() { return createtime; } public void setCreatetime(Date createtime) { this.createtime = createtime; } public String getNote() { return note; } public void setNote(String note) { this.note = note == null ? null : note.trim(); } public User getUser() { return user; } public void setUser(User user) { this.user = user; } public List<Orderdetail> getOrderdetails() { return orderdetails; } public void setOrderdetails(List<Orderdetail> orderdetails) { this.orderdetails = orderdetails; } }
1.3 mapper.xml与mapper对象
由于这是联合查询,映射对象分布在两个对象,因此须要链接两个对象,在Mapper配置文件中用到<association>.
package com.harry.mapper; import java.util.List; import com.harry.entity.Orders; public interface OrdersMapperCustom { public List<Orders> findOrdersUser()throws Exception; }
<?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="com.harry.mapper.OrdersMapperCustom"> <!-- 订单查询关联用户的resultMap 将整个查询的结果映射到com.harry.entity.Orders中 --> <resultMap type="com.harry.entity.Orders" id="OrdersUserResultMap"> <!-- 配置映射的订单信息 --> <!-- id:指定查询列中的惟 一标识,订单信息的中的惟 一标识,若是有多个列组成惟一标识,配置多个id column:订单信息的惟 一标识 列 property:订单信息的惟 一标识 列所映射到Orders中哪一个属性 --> <id column="id" property="id"/> <result column="user_id" property="userId"/> <result column="number" property="number"/> <result column="createtime" property="createtime"/> <result column="note" property="note"/> <!-- 配置映射的关联的用户信息 --> <!-- association:用于映射关联查询单个对象的信息 property:要将关联查询的用户信息映射到Orders中哪一个属性 --> <association property="user" javaType="com.harry.entity.User"> <!-- id:关联查询用户的惟 一标识 column:指定惟 一标识用户信息的列 javaType:映射到user的哪一个属性 --> <id column="user_id" property="id"/> <result column="username" property="username"/> <result column="sex" property="sex"/> <result column="address" property="address"/> </association> </resultMap> <!-- id:statement的id 或者叫作sql的id--> <!-- parameterType:声明输入参数的类型 --> <!-- resultType:声明输出结果的类型,应该填写pojo的全路径 --> <!-- #{}:输入参数的占位符,至关于jdbc的? --> <select id="findOrdersUser" resultMap="OrdersUserResultMap"> SELECT orders.*, user.username, user.sex, user.address FROM user, orders WHERE orders.user_id = user.id </select> </mapper>
1.4 调用OrdersMapperCustom中的方法
@Test public void testQueryOrdersCustomById() throws Exception { // 4. 建立SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 5. 执行SqlSession对象执行查询,获取结果User // 第一个参数是User.xml的statement的id,第二个参数是执行sql须要的参数; List<Orders> orders = sqlSession.selectList("findOrdersUser"); System.out.println(orders.size()); // 6. 打印结果 Iterator i = orders.iterator(); while(i.hasNext()) { System.out.println(i.next()); } // 7. 释放资源 sqlSession.close(); }
1.5 一对一查询结果.
总结:也可使用resultType更简单实现该需求,而后用变量数对应的自定义类进行承接,resultMap能够实现跨对象的嵌套.
resultMap能够实现延迟加载,但resultType没法实现.
需求2 . 查询订单及订单明细的信息(一对多)
2.1sql
肯定查询的主表:订单表
而后肯定关联表:订单明细表
采用resultType方式映射,替订单表加一些订单明细表的映射元素.
SELECT
orders.*,
user.username,
user.sex,
user.address,
orderdetail.id orderdetail_id,
orderdetail.items_id,
orderdetail.items_num,
orderdetail.orders_id
FROM
orders,
user,
orderdetail
WHERE orders.user_id = user.id AND orderdetail.orders_id=orders.id
2.2 映射思路
查询结果出现冗余数据,违背3NF,解决方法是在order类中添加List<OrderDetail>orderDetail属性.
最终会将订单信息映射到orders中,订单所对应的订单明细映射到orders中的orderDetails属性中.
2.3 resultMap定义,关键点在于resultMap将orderdetail多方对象封装在list对象中.
1 <resultMap type="com.harry.entity.Orders" id="OrdersAndDetailResultMap" extends="OrdersUserResultMap"> 2 <!-- 订单信息 --> 3 <!-- 用户信息 --> 4 <!-- 使用extends继承,不用在中配置订单信息和用户信息的映射 --> 5 6 <!-- 订单明细信息 7 一个订单关联查询出了多条明细,要使用collection进行映射 8 collection:对关联查询到多条记录映射到集合对象中 9 property:将关联查询到多条记录映射到com.harry.entity.Orders哪一个属性 10 ofType:指定映射到list集合属性中pojo的类型 11 --> 12 <collection property="orderdetails" ofType="com.harry.entity.Orderdetail"> 13 <!-- id:订单明细惟 一标识 14 property:要将订单明细的惟 一标识 映射到cn.itcast.mybatis.po.Orderdetail的哪一个属性 15 --> 16 <id column="orderdetail_id" property="id"/> 17 <result column="items_id" property="itemsId"/> 18 <result column="items_num" property="itemsNum"/> 19 <result column="orders_id" property="ordersId"/> 20 </collection> 21 </resultMap> 22 23 <select id="findOrdersDetail" resultMap="OrdersAndDetailResultMap"> 24 SELECT 25 orders.*, 26 user.username, 27 user.sex, 28 user.address, 29 orderdetail.id orderdetail_id, 30 orderdetail.items_id, 31 orderdetail.items_num, 32 orderdetail.orders_id 33 FROM 34 orders, 35 user, 36 orderdetail 37 WHERE orders.user_id = user.id AND orderdetail.orders_id=orders.id 38 </select>
需求3. 查询用户和用户购买商品的信息,用户名、用户地址、购买商品名称、购买商品时间、购买商品数量(多对多)
3.1sql
肯定查询的主表:用户表
因为用户和商品没有直接关联,经过订单和订单明细进行关联
而后肯定关联表:orders,orderdetail,items
SELECT
orders.*,
user.username,
user.sex,
user.address,
orderdetail.id orderdetail_id,
orderdetail.items_id,
orderdetail.items_num,
orderdetail.orders_id,
items.name items_name,
items.detail items_detail,
items.price items_price
FROM
orders,
user,
orderdetail,
items
WHERE orders.user_id = user.id AND orderdetail.orders_id=orders.id AND orderdetail.items_id = items.id
3.2映射思路
将用户信息映射到user中.
在user类中添加订单列表属性List<Orders> orderslist,将用户建立的订单映射到orderslist
在Orders中添加订单明细列表属性List<OrderDetail>orderdetials,将订单的明细映射到orderdetials
在OrderDetail中添加Items属性,将订单明细所对应的商品映射到Items
3.3 ResultMap
<resultMap type="com.harry.entity.User" id="UserAndItemsResultMap"> <!-- 用户信息 --> <id column="user_id" property="id"/> <result column="username" property="username"/> <result column="sex" property="sex"/> <result column="address" property="address"/> <!-- 订单信息 一个用户对应多个订单,使用collection映射 --> <collection property="ordersList" ofType="com.harry.entity.Orders"> <id column="id" property="id"/> <result column="user_id" property="userId"/> <result column="number" property="number"/> <result column="createtime" property="createtime"/> <result column="note" property="note"/> <!-- 订单明细 一个订单包括 多个明细 --> <collection property="orderdetails" ofType="com.harry.entity.Orderdetail"> <id column="orderdetail_id" property="id"/> <result column="items_id" property="itemsId"/> <result column="items_num" property="itemsNum"/> <result column="orders_id" property="ordersId"/> <!-- 商品信息 一个订单明细对应一个商品 --> <association property="items" javaType="com.harry.entity.Items"> <id column="items_id" property="id"/> <result column="items_name" property="name"/> <result column="items_detail" property="detail"/> <result column="items_price" property="price"/> </association> </collection> </collection> </resultMap> <select id="findUserItems" resultMap="UserAndItemsResultMap"> SELECT orders.*, user.username, user.sex, user.address, orderdetail.id orderdetail_id, orderdetail.items_id, orderdetail.items_num, orderdetail.orders_id, items.name items_name, items.detail items_detail, items.price items_price FROM orders, user, orderdetail, items WHERE orders.user_id = user.id AND orderdetail.orders_id=orders.id AND orderdetail.items_id = items.id </select>
这两种配置方式均可以实现映射,但应用的场景存在差异
ResultType更容易实现映射关系,仅仅只要有对应的变量进行存储,只要扩展pojo便可(需求一)
ResultMap须要定义特定的ResultMap,这种适用于pojo处理多对多映射关系,一对可能是多对多的一种特殊状况(需求二)
需求一:
查询字段:用户帐号、用户名称、用户性别、商品名称、商品价格(最多见)
企业开发中常见明细列表,用户购买商品明细列表,
使用resultType将上边查询列映射到pojo输出.
需求二:
查询字段:用户帐号、用户名称、购买商品数量、商品明细(鼠标移上显示明细)
使用resultMap将用户购买的商品明细列表映射到user对象中.
resultMap能够实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具有延迟加载功能.
延迟加载:先从单表查询、须要时再从关联表去关联查询,大大提升 数据库性能,由于查询单表要比关联查询多张表速度要快.
(举例)使用association实现延迟加载
1.需求:查询订单而且关联查询用户信息
主表 : orders表
关联表 : user表
2.思路:定义两个单独的mapper对应的两个表
<!-- 查询订单关联查询用户,用户信息须要延迟加载 --> <select id="findOrdersUserLazyLoading" resultMap="OrdersUserLazyLoadingResultMap"> SELECT * FROM orders </select> ------------------------------------------------------------------------------------------------------ <select id="findUserById" parameterType="int" resultType="user"> SELECT * FROM USER WHERE id=#{value} </select>
3.使用定义了延迟加载的resultMap
<!-- 延迟加载的resultMap --> <resultMap type="com.harry.entity.Orders" id="OrdersUserLazyLoadingResultMap"> <!--对订单信息进行映射配置 --> <id column="id" property="id"/> <result column="user_id" property="userId"/> <result column="number" property="number"/> <result column="createtime" property="createtime"/> <result column="note" property="note"/> <!-- 实现对用户信息进行延迟加载 select:指定延迟加载须要执行的statement的id(是根据user_id查询用户信息的statement) 要使用userMapper.xml中findUserById完成根据用户id(user_id)用户信息的查询,若是findUserById不在本mapper中须要前边加namespace column:订单信息中关联用户信息查询的列,是user_id 关联查询的sql理解为: SELECT orders.*, (SELECT username FROM user WHERE orders.user_id = user.id)username, (SELECT sex FROM user WHERE orders.user_id = user.id)sex FROM orders --> <association property="user" javaType="com.harry.entityUser" select="com.harry.mapper.UserMapper.findUserById" column="user_id"> <!-- 实现对用户信息进行延迟加载 --> </association> </resultMap>
4.测试思路是分两个mapper来进行调用,先调用getOrders(),而后再调用getUser();
5.延迟加载配置
mybatis默认没有开启延迟加载,须要在SqlMapConfig.xml中setting配置.
在mybatis核心配置文件中配置:
lazyLoadingEnabled、aggressiveLazyLoading
<!-- 全局配置参数,须要时再设置 --> <settings> <!-- 打开延迟加载 的开关 --> <setting name="lazyLoadingEnabled" value="true"/> <!-- 将积极加载改成消极加载即按须要加载 --> <setting name="aggressiveLazyLoading" value="false"/> <!-- 开启二级缓存 --> <setting name="cacheEnabled" value="true"/> </settings>
查询缓存介绍
mybatis提供查询缓存,用于减轻数据压力,提升数据库性能.mybaits提供一级缓存,和二级缓存.
由上图能够看清mybatis缓存机制
1.一级缓存存在于每一个sqlSession之中,缓存自动启动,语句commit为缓存刷新
@Test public void testCache1() throws Exception{ SqlSession sqlSession = sqlSessionFactory.openSession();//建立代理对象 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //下边查询使用一个SqlSession //第一次发起请求,查询id为1的用户 User user1 = userMapper.findUserById(1); System.out.println(user1); // 若是sqlSession去执行commit操做(执行插入、更新、删除),清空SqlSession中的一级缓存,这样作的目的为了让缓存中存储的是最新的信息,避免脏读。 //更新user1的信息 user1.setUsername("测试用户22"); userMapper.updateUser(user1); //执行commit操做去清空缓存 sqlSession.commit(); //第二次发起请求,查询id为1的用户 User user2 = userMapper.findUserById(1); System.out.println(user2); sqlSession.close(); }
2.二级缓存存在于sqlSession之间,缓存需手动开启,sqlSession一关闭缓存刷新,关闭二级缓存设置useCache
开启缓存:<setting name="cacheEnabled" value="true"/>
// 二级缓存测试 @Test public void testCache2() throws Exception { SqlSession sqlSession1 = sqlSessionFactory.openSession(); SqlSession sqlSession2 = sqlSessionFactory.openSession(); SqlSession sqlSession3 = sqlSessionFactory.openSession(); // 建立代理对象 UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class); // 第一次发起请求,查询id为1的用户 User user1 = userMapper1.findUserById(1); System.out.println(user1); //这里执行关闭操做,将sqlsession中的数据写到二级缓存区域 sqlSession1.close(); //使用sqlSession3执行commit()操做 UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class); User user = userMapper3.findUserById(1); user.setUsername("张明明"); userMapper3.updateUser(user); //执行提交,清空UserMapper下边的二级缓存 sqlSession3.commit(); sqlSession3.close(); UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class); // 第二次发起请求,查询id为1的用户 User user2 = userMapper2.findUserById(1); System.out.println(user2); sqlSession2.close();
关闭特定Mapper缓存<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
分布式缓存
咱们系统为了提升系统并发性能,通常对系统进行分布式部署(集群部署方式).
假定这时某个用户在一台服务器登陆了系统,怎么去通知服务器群该用户的访问权限?
二级缓存的应用场景
对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术下降数据库访问量,提升访问速度,业务场景好比:耗时较高的统计分析sql、电话帐单查询sql等。
实现方法以下:经过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,好比设置为30分钟、60分钟、24小时等,根据需求而定。
mybatis自身没有实现分布式缓存机制,但提供了接口去整合其余分布式缓存框架.
整合思路
使用springi以单例模式管理sqlSessionFactory
使用sqlSessionFactory建立sqlSession(spring和mybatis整合自动完成)
持久层mapper使用spring容器进行管理
整合准备
maven引进mysql,spring core, aop, mybatis, mybatis-spring等jar
sqlSessionFactory
在applicationContext中配置sqlSessionFactory和数据源
<!-- 加载配置文件 --> <context:property-placeholder location="classpath:db.properties" /> <!-- 数据源,使用dbcp --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <property name="maxActive" value="10" /> <property name="maxIdle" value="5" /> </bean> <!-- sqlSessinFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 加载mybatis的配置文件 --> <property name="configLocation" value="mybatis/SqlMapConfig.xml" /> <!-- 数据源 --> <property name="dataSource" ref="dataSource" /> </bean>
mapper和mapper.xml
生成特定的mapper和mapper.xml(略)
经过MapperScannerConfigure进行mapper扫描
<!-- mapper批量扫描,从mapper包中扫描出mapper接口,自动建立代理对象而且在spring容器中注册 遵循规范:将mapper.java和mapper.xml映射文件名称保持一致,且在一个目录 中 自动扫描出来的mapper的bean的id为mapper类名(首字母小写) --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- 指定扫描的包名 若是扫描多个包,每一个包中间使用半角逗号分隔 --> <property name="basePackage" value="com.harry.ssm.mapper"/> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> </bean>
1.什么是逆向工程?
正向工程 : Entity --> Table
逆向工程 : Table --> Entity
逆向工程就是使用数据库表来反向生成实体类和映射文件
2.修改配置
Mybatis官方提供了逆向工具,指定其代码配置文件四个位置,entity,mapper,mapper.xml的所在位置,最后指定想生成的数据库表.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <context id="testTables" targetRuntime="MyBatis3"> <commentGenerator> <!-- 是否去除自动生成的注释 true:是 : false:否 --> <property name="suppressAllComments" value="true" /> </commentGenerator> <!--数据库链接的信息:驱动类、链接地址、用户名、密码 --> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root" password="mysql"> </jdbcConnection> <!-- <jdbcConnection driverClass="oracle.jdbc.OracleDriver" connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg" userId="yycg" password="yycg"> </jdbcConnection> --> <!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和 NUMERIC 类型解析为java.math.BigDecimal --> <javaTypeResolver> <property name="forceBigDecimals" value="false" /> </javaTypeResolver> <!-- targetProject:生成PO类的位置 --> <javaModelGenerator targetPackage="com.harry.ssm.entity" targetProject=".\src"> <!-- enableSubPackages:是否让schema做为包的后缀 --> <property name="enableSubPackages" value="false" /> <!-- 从数据库返回的值被清理先后的空格 --> <property name="trimStrings" value="true" /> </javaModelGenerator> <!-- targetProject:mapper映射文件生成的位置 --> <sqlMapGenerator targetPackage="com.harry.ssm.mapper" targetProject=".\src"> <!-- enableSubPackages:是否让schema做为包的后缀 --> <property name="enableSubPackages" value="false" /> </sqlMapGenerator> <!-- targetPackage:mapper接口生成的位置 --> <javaClientGenerator type="XMLMAPPER" targetPackage="com.harry.ssm.mapper" targetProject=".\src"> <!-- enableSubPackages:是否让schema做为包的后缀 --> <property name="enableSubPackages" value="false" /> </javaClientGenerator> <!-- 指定数据库表 --> <table tableName="items"></table> <table tableName="orders"></table> <table tableName="orderdetail"></table> <table tableName="user"></table> </context> </generatorConfiguration>
3.修改并执行下载程序