用户表和订单表的关系为: 一个用户有多个订单,一个订单只从属于一个用户 一对一查询的需求: 查询一个订单,与此同时查询出该订单所属用户
可以在上节课的环境下接着下面的操作,我就是这样的。虽然下面写的环境搭建是全部操作,但是如果你用上节课的环境的话,第4、5、6、8步就不需要跟着我做了
具体过程:
第一步: 确保数据库的test库里面有user表(上节课的)和orders表,并且orders表内是如下数据
create table orders(
id int primary key auto_increment comment '主键',
ordertime date comment '订单创建时间',
total int comment '订单总数',
uid int comment '外键',
constraint fk_userid foreign key (uid) references user(id)
) comment '订单表';
insert into orders values
(null,'2019-02-15 14:59:37',3000,1),(null,'2018-10-10 15:00:01',5800,1),(null,'2019-02-28 15:00:15',323,2),
(null,'2019-02-21 15:00:27',2345,1),(null,'2019-02-04 15:00:40',100,2),(null,'2018-06-07 15:00:56',2009,3);
第二步: 在src/main/java目录下新建domain.Order类,写入如下
//订单的实体类,对应的是数据库的orders表
public class Order {
private int id;
private Date ordertime;
private double total;
private User user; //这个表示的是orders的uid外键(订单属于user表的用户)
//get和set方法
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Date getOrdertime() {
return ordertime;
}
public void setOrdertime(Date ordertime) {
this.ordertime = ordertime;
}
public double getTotal() {
return total;
}
public void setTotal(double total) {
this.total = total;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
//toString方法
public String toString() {
return "Order{" +
"id=" + id +
", ordertime=" + ordertime +
", total=" + total +
", user=" + user +
'}';
}
}
第三步: 在src/main/java目录下新建mapper.OrderMapper接口,写入如下
public interface OrderMapper { public List<Order> findAll(); }
第四步: 在src/main/resources目录下新建File,文件名为jdbc.properties,写入如下
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=228675
第五步: 在src/main/resources目录下新建File,文件名为log4j.properties,写入如下
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c:/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=debug, stdout
第六步: 在src/main/resources目录下新建File,文件名为sqlMapConfig.xml,写入如下
<configuration>
<!--通过properties标签加载外部(resources目录)配置的properties文件-->
<properties resource="jdbc.properties"></properties>
<!--为UserMapper.xml里面的resultType、parameterType属性需要的全限定名,设置别名为user-->
<typeAliases>
<typeAlias type="com.huanf.domain.User" alias="user"></typeAlias>
<typeAlias type="com.huanf.domain.Order" alias="order"></typeAlias>
</typeAliases>
<!--配置数据源环境。default表示默认情况下使用的是哪个环境,例如development,环境名是自定义的-->
<!--transactionManager指的是你要用哪种事务管理器,例如原生JDBC。dataSource指的是你要用哪种数据源,例如连接池POOLED-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<!--下面那行的'?useSSL=false&useUnicode=true&characterEncoding=UTF-8'可写可不写-->
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!--加载映射文件-->
<mappers>
<mapper resource="com/huanf/mapper/UserMapper.xml"></mapper>
<mapper resource="com/huanf/mapper/OrderMapper.xml"></mapper>
</mappers>
</configuration>
第七步: 在src/main/resources目录下新建com/huanf/mapper目录,里面新建OrderMapper,xml,写入如下
xxxxxxxxxx
<mapper namespace="com.huanf.mapper.OrderMapper">
</mapper>
第八步: 在pom.xml里面写入如下
<dependencies>
<!--数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
<!--引入MyBatis坐标-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--引入Junit坐标,用于测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--引入log4j,用于打印日志-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
具体操作如下:
第一步: 在src/main/java/com.huanf/domain目录新建User类,写入如下
//数据库中的user表数据
public class User {
//对应表中的字段
private int id;
private String username;
private String password;
//用于数据转换
private Date birthday;
//get和set方法
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 getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", birthday=" + birthday +
'}';
}
}
第二步: 在src/main/resources目录下新建com/huanf/mapper目录,里面新建OrderMapper.xml,写入如下
x
<mapper namespace="com.huanf.mapper.OrderMapper">
<!--resultMap标签用于手动指定字段与实体属性之间的映射关系。下面那行的type写Order类的全限定名,或者写别名-->
<resultMap id="zidingyi_orderMap" type="order">
<!--手动指定字段与实体属性(也就是Order类的成员变量)的映射关系。column表示字段名称,property表示实体属性的名称-->
<!--主键字段,用id标签,column表示查询的oid字段,property表示oid对应的是'Order类的id成员变量'-->
<id column="oid" property="id"></id>
<!--其它普通字段用result标签,column表示查询的ordertime字段,property表示ordertime对于的是'Order类的ordertime成员变量'-->
<result column="ordertime" property="ordertime"></result>
<!--其它普通字段用result标签,column表示查询的total字段,property表示total对于的是'Order类的total成员变量'-->
<result column="total" property="total"></result>
<!--其它普通字段用result标签,column表示查询的uid字段,property表示uid对于的是'Order类的user对象的id成员变量'-->
<result column="uid" property="user.id"></result>
<!--其它普通字段用result标签,column表示查询的username字段,property表示username对于的是'Order类的user对象的username成员变量'-->
<result column="username" property="user.username"></result>
<result column="password" property="user.password"></result>
<result column="birthday" property="user.birthday"></result>
</resultMap>
<!--把查询到的结果放到resultMap属性里面,该属性值就是上面resultMap标签的id值,有resultMap标签帮我们把查询到的数据对应到所属字段-->
<select id="findAll" resultMap="zidingyi_orderMap">
<!--这里定义oid别名,上面的resultMap标签必须使用这里定义的uid、oid别名-->
select *,o.id oid from orders o,user u where o.uid=u.id;
</select>
</mapper>
第三步: 在src/main/resources的com/huanf/mapper目录,里面新建UserMapper.xml,写入如下
<mapper namespace="com.huanf.mapper.UserMapper">
</mapper>
第四步: 在src/test/java目录下新建com.huanf.test目录,里面新建MyBatisTest类,写入如下,并执行测试test1
public class MyBatisTest {
public void test1() throws IOException {
//获得核心配置文件。注意写的是相对路径,也就是src/main/resources/sqlMapConfig.xml
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//获得session工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得session会话对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//使用getMapper获得mapper代理对象
OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
List<Order> orderList = mapper.findAll();
for (Order order : orderList) {
System.out.println(order);
}
sqlSession.close();
}
}
具体操作:
第一步: 将OrderMapper.xml修改为如下
xxxxxxxxxx
<mapper namespace="com.huanf.mapper.OrderMapper">
<!--下面描述中,实体指的是Order类,属性名指的是Order类的成员变量名-->
<!--resultMap标签用于手动指定字段与实体属性之间的映射关系。下面那行的type写Order类的全限定名,或者写别名-->
<resultMap id="zidingyi_orderMap" type="order">
<!--手动指定字段与实体属性(也就是Order类的成员变量)的映射关系。column表示字段名称,property表示实体属性的名称-->
<!--主键字段,用id标签,column表示查询的oid字段,property表示oid对应的是'Order类的id成员变量'-->
<id column="oid" property="id"></id>
<!--其它普通字段用result标签,column表示查询的ordertime字段,property表示ordertime对于的是'Order类的ordertime成员变量'-->
<result column="ordertime" property="ordertime"></result>
<!--其它普通字段用result标签,column表示查询的total字段,property表示total对于的是'Order类的total成员变量'-->
<result column="total" property="total"></result>
<!--其它普通字段用result标签,column表示查询的uid字段,property表示uid对于的是'Order类的user对象的id成员变量'-->
<!--下面那段是一对一的第一种写法,我注释了,如果注释的话,就使用第二种写法。注意这两种代码用其中一种就行,其他代码不用动-->
<!--<result column="uid" property="user.id"></result>
<!–其它普通字段用result标签,column表示查询的username字段,property表示username对于的是'Order类的user对象的username成员变量'–>
<result column="username" property="user.username"></result>
<result column="password" property="user.password"></result>
<result column="birthday" property="user.birthday"></result>-->
<!--第二种写法。由于第一种写法里面的user属性被写了4行,所以为简化,我们把user属性(其实就是Order类的user成员变量)抽取到property里面-->
<!--javaType的值填写的是user属性的类型(是User类型),写该类型的全限定名,或者写别名-->
<!--注意再重复一遍,user填写的是属性名,例如Order类的user成员变量。javaType填写的是属性名对应的类型,例如User类,那就写User类的全限定名或者别名-->
<association property="user" javaType="user">
<!--column表示查询出来的uid字段,property表示uid对应的是'User类的id成员变量'-->
<id column="uid" property="id"></id>
<!--column表示查询出来的username字段,property表示username对应的是'User类的username成员变量'-->
<result column="username" property="username"></result>
<result column="password" property="password"></result>
<result column="birthday" property="birthday"></result>
</association>
</resultMap>
<!--把查询到的结果放到resultMap属性里面,该属性值就是上面resultMap标签的id值,有resultMap标签帮我们把查询到的数据对应到所属字段-->
<select id="findAll" resultMap="zidingyi_orderMap">
<!--这里定义oid别名,上面的resultMap标签必须使用这里定义的uid、oid别名-->
select *,o.id oid from orders o,user u where o.uid=u.id;
</select>
</mapper>
第二步: 在MyBatisTest类,执行测试test1
到此,一对一模型我们已经学习完毕,接下来是一对多和多对多
用户表和订单表的关系为: 一个用户有多个订单,一个订单只从属于一个用户 一对多查询的需求: 查询一个用户,与此同时查询出该用户具有的多个订单
注意我们会继续使用上面一对一模型的数据库数据,以及已经写了的代码。具体操作如下
第一步: 由于我们之前做过时间类型转换的演示,所以为不影响这节课的演示,我们将上次做的时间类型转换演示产生的数据删掉
delete from user where username = '测试';
第二步: 在src/main/java/com.huanf/mapper目录下新建UserMapper接口,写入如下
public interface UserMapper {
public List<User> findAll();
}
第三步: 在User类添加如下,并添加对应的get和set方法,以及toString方法
//描述的是当前用户存在哪些订单
private List<Order> orderList;
第四步: 将UserMapper.xml修改为如下
x
<mapper namespace="com.huanf.mapper.UserMapper">
<!--同样是配置查询出来的结果,跟数据库字段的映射关系。这里就不写多余注释了,跟OrderMapper.xml里面写的一样-->
<resultMap id="zidingyi2_orderMap" type="user">
<id column="uid" property="id"></id>
<result column="username" property="username"></result>
<result column="password" property="password"></result>
<result column="birthday" property="birthday"></result>
<!--配置集合。property表示集合名称(User类的orderList成员变量),
ofType表示当前集合的数据类型(User类的orderList成员变量的数据类型,例如泛型为Order类型,就写Order的全限定名或别名)-->
<collection property="orderList" ofType="order">
<!--封装order的数据-->
<id column="oid" property="id"></id>
<result column="ordertime" property="ordertime"></result>
<result column="total" property="total"></result>
</collection>
</resultMap>
<!--一对多查询模型-->
<select id="findAll" resultMap="zidingyi2_orderMap">
select *,o.id oid from user u,orders o where u.id=o.uid;
</select>
</mapper>
第五步: 在MyBatisTest类添加如下,并执行测试test2
//一对多查询模型
public void test2() throws IOException {
//获得核心配置文件。注意写的是相对路径,也就是src/main/resources/sqlMapConfig.xml
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//获得session工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得session会话对象
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.findAll();
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
用户表和角色表的关系为: 一个用户有多个角色,一个角色被多个用户使用 多对多查询的需求: 查询用户同时查询出该用户具备的所有角色
多对多模型环境搭建,具体操作如下
第一步: 在你的D盘新建ssm_a_16_0_test.sql目录,里面放入test.sql文件。打开datagrip软件,右键你的@localhost数据库服务,点击Run SQL Script,选择你的test.sql文件路径,然后回车,你的数据库就会多一个test库。我已经把test.sql文件打包放到"SSM框架\阅读\a_16_0素材"里面。 简单概括一下: 这一步,我们需要导入test.sql文件的数据,实际用的时候,我们只需要用的里面的sys_role、sys_user_role表,以及上面一直演示的user表。共3张表,不用管sys_user_role是谁的中间表
第二步: 新建Role类,写入如下
x
//对应的是数据库的sys_role角色表
public class Role {
private int id;
private String roleName;
private String roleDesc;
//get和set方法
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getRoleDesc() {
return roleDesc;
}
public void setRoleDesc(String roleDesc) {
this.roleDesc = roleDesc;
}
public String toString() {
return "Role{" +
"id=" + id +
", roleName='" + roleName + '\'' +
", roleDesc='" + roleDesc + '\'' +
'}';
}
}
第三步: 在User类添加如下,并添加对应的get和set方法,以及toString方法
//描述的是当前用户具备哪些角色
private List<Role> roleList;
第四步: 在UserMapper接口添加如下
//一对多查询
public List<User> findUserAndRoleAll();
第五步: 在sqlMapConfig.xml添加如下
<typeAlias type="com.huanf.domain.Role" alias="role"></typeAlias>
第六步: 在UserMapper.xml添加如下
<!--同样是配置查询出来的结果,跟数据库字段的映射关系。这里就不写多余注释了,跟OrderMapper.xml里面写的一样-->
<resultMap id="zidingyi3_orderMap" type="user">
<!--user信息-->
<id column="userId" property="id"></id>
<result column="username" property="username"></result>
<result column="password" property="password"></result>
<result column="birthday" property="birthday"></result>
<!--配置集合。property表示集合名称(User类的roleList成员变量),
ofType表示当前集合的数据类型(User类的roleList成员变量的数据类型,例如泛型为Role类型,就写Role的全限定名或别名)-->
<collection property="roleList" ofType="role">
<!--封装Role类的成员变量。column是查询到的数据(查询到的字段),property是数据对应的字段(Role类的成员变量)-->
<id column="roleId" property="id"></id>
<result column="roleName" property="roleName"></result>
<result column="roleDesc" property="roleDesc"></result>
</collection>
</resultMap>
<!--多对多查询模型-->
<select id="findUserAndRoleAll" resultMap="zidingyi3_orderMap">
<!--内连接查询,只查询有角色的用户。如果改为左外连接查询,就会把没有角色的用户、有角色的用户都查询出来。下面那行的sql语句是内连接查询-->
select * from user u,sys_user_role ur,sys_role r where u.id=ur.userId and ur.roleId=r.id;
</select>
第七步: 在MyBatisTest添加如下,执行测试test3
//多对多查询模型
public void test3() throws IOException {
//获得核心配置文件。注意写的是相对路径,也就是src/main/resources/sqlMapConfig.xml
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
//获得session工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得session会话对象
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userAndRoleAll = mapper.findUserAndRoleAll();
for (User user : userAndRoleAll) {
System.out.println(user);
}
sqlSession.close();
}