文章目录
- 1.mybatis-config.xml核心配置文件中标签:test -> interface/impl -> sql
- 2.UserMapper.xml映射文件中增删改查标签:动态代理规定namespace,id
- 3.UserMapper.xml
- 4.mapper:UserMapper.java
- 5.test:UserMapperTest.java
- 6.OrderMapper.xml:用u,订o,详d,商i
- 7.domain:order.java,Orderdetail .java
- 8.mapper:OrderMapper.java
- 9.test:OrderMapperTest.java
- 10.mapper:UserMapper.java,OrderMapper.java,OrderDetailMapper.java,ItemMapper.java
- 11.test:UserMapperTest.java,OrderMapperTest.java
- 12.动态sql注解开发
1.mybatis-config.xml核心配置文件中标签:test -> interface/impl -> sql
//jdbc.properties文件,如下前面加上jdbc.是防止如上 ${}字符串拼接 拿到下面参数,没有拿到方法中参数
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=root
//mybatis-config.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>
<!--
1.将jdbc.properties配置文件加载到mybatis的环境中。
2.通过${key}读取配置文件中的配置信息
properties声明属性的2种方式:1.resource:相对路径引入外部的properties配置文件
2.property子标签来动态声明
-->
<properties resource="jdbc.properties"> <!--在下面第二个environment标签里用到-->
<!--<property name="username" value="root"></property>--> <!--这行也可以,和maven里版本声明一样,不用外部jdbc.properties文件,优先级最低-->
</properties>
<!--111111111111111111111111111111111111111111111111111111111111111111111111111111111-->
<settings>
<!--开启驼峰映射,经典的映射规范 : 数据库列名A_COLUMN (小写就行) ————> java属性名aColumn-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!--111111111111111111111111111111111111111111111111111111111111111111111111111111111-->
<typeAliases> <!--类型别名:如下两种方式:这样UserMapper.xml中resultType="User"就行-->
<!-- 第一种配置方式:typeAlias标签配置单个别名 -->
<!--<typeAlias type="com.itheima.domain.User" alias="User"></typeAlias>-->
<!-- 第二种配置方式:常用,包扫描 ,默认类名就是别名-->
<package name="com.itheima.domain"></package>
</typeAliases>
<!--111111111111111111111111111111111111111111111111111111111111111111111111111111111-->
<!-- 数据源环境:下行default: 默认采用的环境即数据源配置的环境的id,可换成下面test。-->
<environments default="development">
<!-- 配置单个数据源环境,id是当前环境配置的唯一标识。development开发环境,dist生产环境 -->
<environment id="development">
<!--
如下事务管理: type: JDBC or MANAGED
JDBC: 采用jdbc的事务管理。 底层connection.commit/.rollback
MANAGED: 不采用事务。
-->
<transactionManager type="JDBC"/> <!--采用事务-->
<!---->
<!--
如下配置数据源的具体链接参数:
type: POOLED: 支持连接池配置,除了最基本的数据源连接参数配置,
还可以配置连接池相关的参数如:最大连接数,最大空闲连接数...
UNPOOLED: 不支持连接池配置。
-->
<dataSource type="POOLED"> <!--#{}被动传,${}主动取/拼接-->
<property name="driver" value="${jdbc.driverClass}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
<!--//-->
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driverClass}"/>
<property name="url" value="${url}"/>
<property name="username" value="aaa"/>
<property name="password" value="bbb"/>
</dataSource>
</environment>
</environments>
<!--111111111111111111111111111111111111111111111111111111111111111111111111111111111-->
<mappers> <!--告知mybatis映射文件的位置,一般一个接口对应一个xxxMapper映射文件-->
<!-- 第一种配置: 相对路径配置映射文件的位置 -->
<!--<mapper resource="UserMapper.xml"/>-->
<!-- 第二种配置:url绝对路径方式,肯定不用 -->
<!-- <mapper url="file:///var/mappers/AuthorMapper.xml"/>-->
<!-- 第三种配置:采用接口的全路径配置方式
此处注意:虽然配置的是类的全路径,但是我们都知道,io流读取资源的本质都是需要知道
文件的名字和位置。
所以: 我们需要通过接口的全路径 com.itheima.mapper.UserMapper
能够知道接口对应的映射文件的 位置 和 名字。
文件的位置和名字必须得满足2个规范: 1.mapper文件名 必须和 接口的名字 一致。
2.mapper文件 必须和 接口 放在同一个包下。
所以将UserMapper.xml和UserMapper.java文件放在com.itheima.mapper文件夹下
-->
<!-- <mapper class="com.itheima.mapper.UserMapper"></mapper>-->
<!-- 第四种配置:包扫描方式 ,基于第三种的规范。-->
<!-- <package name="com.itheima.mapper"></package>-->
<!--要么第一种,要么第四种,如下第一种-->
<mapper resource="com/itheima/mapper/UserMapper.xml"></mapper>
<mapper resource="com/itheima/mapper/commonSql.xml"></mapper> <!--不要忘了引入-->
</mappers>
</configuration>
2.UserMapper.xml映射文件中增删改查标签:动态代理规定namespace,id
mybatis-config.xml中< typeAliases > 和< mappers > 规定resultType和文件名。
2.1 UserMapper.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">
<mapper namespace="com.itheima.mapper.UserMapper">
<!--
select: 查询的statement(声明),用来编写查询语句
id: 语句的唯一标识
resultType:配置返回的结果集类型
parameterType:传递的参数类型,可以省略
-->
<select id="findUserById" resultType="User">
select * from tb_user where id = #{a}
</select>
<!--
useGeneratedKeys=true, 开启主键的自动回显。(主键必须是自增长的)
keyProperty="id" 主键属性值回显到的实体的属性名 //user对象的id属性
keyColumn="id" 主键的列名
-->
<insert id="addUser" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
insert into tb_user(user_name,password,name) values(#{userName},#{password},#{name})
</insert>
<!--
#{} : 预编译的传参方式
1.如果传递 单个 基本类型参数,sql语句中的参数名可以是任意名称,如上findUserById中#{a}
2.如果传递的是多个基本类型参数
a. #{arg0} #{arg1} 或者 #{param1} #{param2} 获取方法传递的参数(不推荐)
b. 注解方式(推荐),在方法的参数上使用@Param(参数名),
在sql语句中 #{参数名} 来引入 方法调用时 传递的参数,两参数名要一样。
3.对象类型的参数:#{property} property就是对象的属性名。
4.Hash类型的参数:#{key} key就是map集合中的key。
${} : 字符串拼接方式,格式和获取properties配置中的参数语法${}一致,所以加jdbc.区分。
#{} 预编译方式,参数在传递时,如果是字符串,会自动添加''。预编译可预防sql注入,但是传的参数是sql语句关键字就不行了。
-->
<select id="findUserByPasswordAndSex" resultType="User">
select * from tb_user where password=#{p} and sex=#{sex}
</select>
<select id="findUserByUsername" resultType="User">
select * from tb_user where user_name = #{username}
</select>
<select id="findUserByHash" resultType="User">
select * from tb_user where password=#{password} and sex=#{sex}
</select>
<select id="findUserByTable" resultType="User">
select * from ${tableName}
</select>
<select id="findUserLikeUsername" resultType="User">
select * from tb_user where user_name like #{username}
</select>
<!--1111111111111111111111111111111111111111111111111111111111111111111111111111111-->
<select id="findUsersBySex" resultMap="myResultMap">
<!-- 自定义结果集映射:resultMap: 自定义结果集的id -->
select <include refid="commonSql.mySql"></include> from tb_user where sex = #{sex}
</select>
<!--
id:自定义结果集的唯一标识
type: 类型。实体的类型,支持别名写法
autoMapping="true" 自动映射,
默认值为true,那么会将列名和属性名一致的进行自动映射。
值为false,只会将我们配置的列进行映射,没有配置的列不进行映射
-->
<resultMap id="myResultMap" type="User" autoMapping="false">
<!--
配置主键和属性的映射的
column:主键的列名
property:实体的属性名
-->
<id column="uid" property="id"></id>
<!-- 如下配置非主键的列的映射的 -->
<result column="user_name" property="userName"></result>
<result column="uage" property="age"></result>
</resultMap>
<!--11111111111111111111111111111111111111111111111111111111111111111111111111111111-->
<!--
sql片段:类似抽成函数方法,反复调用
1.通过<sql>标签来声明一段通用sql
2.在执行sql时,通过<include refid="namespace.sqlId">来引入声明好的sql
如下<include refid="mySql"></include>就行
-->
<sql id="mySql">
*,age uage,id uid
</sql>
<!--11111111111111111111111111111111111111111111111111111111111111111111111111111111-->
<select id="findUsersByAge" resultType="User"> <!--xml中不能写<号-->
select * from tb_user where age <![CDATA[ < ]]> #{age}
<!-- select * from tb_user where age < #{age} -->
</select>
</mapper>
//commonSql.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">
<mapper namespace="commonSql">
<sql id="mySql">
*,age uage,id uid
</sql>
</mapper>
2.2 mapper:UserMapper.java
生成订单详情需要订单的标识id,插入数据库才有id,这个id也只存在数据库中。
package com.itheima.mapper;
import com.itheima.domain.User;
import org.apache.ibatis.annotations.Param;
import java.util.HashMap;
import java.util.List;
public interface UserMapper {
public List<User> findUserByUsername(@Param("username") String username);
public void addUser(User user);
public User findUserById(int id);
public List<User> findUserByPasswordAndSex(@Param("p") String password, @Param("sex") int sex);
public List<User> findUserByHash(HashMap<String,Object> map);
// 实际开发中有分表分库,分表:mysql中一张表存储数据是百万级别性能是最好的。
// 如下1千万信息放一张表性能低,所以分表两张表,根据表名查询用户的信息
public List<User> findUserByTable(@Param("tableName") String tableName);
public List<User> findUserLikeUsername(@Param("username") String username);
// 如下自定义结果集(驼峰映射和起别名不起作用)
public List<User> findUsersBySex(@Param("sex") int sex);
// 如下查询年龄小于某个指定的值的用户信息
public List<User> findUsersByAge(@Param("age") int age);
}
2.3 test:UserMapperTest.java
package com.itheima.mapper;
import com.itheima.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import static org.junit.Assert.*;
public class UserMapperTest {
private UserMapper userMapper;
@Before
public void setUp() throws Exception {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
userMapper = sqlSession.getMapper(UserMapper.class);
}
@Test
public void findUserById() {
User user = userMapper.findUserById(1);
System.out.println(user);
}
@Test
public void addUser(){
User user = new User();
user.setUserName("zhangwuji");
user.setPassword("zhaoming");
user.setName("zhouzhiruo");
userMapper.addUser(user); //user没有id信息,但UserMapper.xml中配置了主键id回显
System.out.println(user.getId()); //执行后数据库插入一条id=9, 删除id=9, 插入一条id=10不是9
}
@Test
public void findUserByPasswordAndSex(){
String password = "123456";
int sex = 1;
List<User> userList = userMapper.findUserByPasswordAndSex(password, sex);
for(User user:userList){
System.out.println(user);
}
}
@Test
public void findUserByUsername(){
List<User> userList = userMapper.findUserByUsername("lisi");
for(User user:userList){
System.out.println(user);
}
}
@Test
public void findUserByHash(){
HashMap<String,Object> map = new HashMap<>();
map.put("pwd","123456");
map.put("sex","1");
List<User> userList = userMapper.findUserByHash(map);
for(User user:userList){
System.out.println(user);
}
}
@Test
public void findUserByTable(){
String tableName = "tb_user_copy";
List<User> userList = userMapper.findUserByTable(tableName);
for(User user:userList){
System.out.println(user);
}
}
@Test
public void findUserLikeUsername(){
String username = "%zhang%";
List<User> userList = userMapper.findUserLikeUsername(username);
for(User user:userList){
System.out.println(user);
}
}
@Test
public void findUsersBySex(){
List<User> userList = userMapper.findUsersBySex(1);
for(User user:userList){
System.out.println(user);
}
}
@Test
public void findUsersByAge(){
List<User> userList = userMapper.findUsersByAge(30);
for(User user:userList){
System.out.println(user);
}
}
}
如上正确产生如下。
如下要加引号。
如下字符串拼接。
3.UserMapper.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">
<mapper namespace="com.itheima.mapper.UserMapper">
<cache></cache>
<!-- if标签,条件判断,test属性写上条件判断的表达式 -->
<select id="findUsersByUsername" resultType="User">
select * from tb_user where sex = 1
<if test="username !=null and username.trim()!=''"> <!-- null空对象,''空串 -->
and user_name like #{username}
</if>
</select>
<!-- choose when otherwise :从上往下,只会选择其中的第一个满足的条件 -->
<select id="findUsersByUsernameOrAge" resultType="User">
select * from tb_user where sex = 1
<choose>
<when test="username!=null and username.trim()!=''">
and user_name like #{username}
</when>
<when test="age>0">
and age > #{age}
</when>
<otherwise>
and user_name = 'zhangsan'
</otherwise>
</choose>
</select>
<!-- where标签自动添加where关键字在tb_user后,并且自动移除多余的and或者or。也可以去掉where标签并在tb_user后加where 1=1 -->
<select id="findUsersByUsernameAndAge" resultType="User">
select * from tb_user
<where>
<if test="username!=null and username.trim()!=''">
and user_name like #{username}
</if>
<if test="age>0">
and age > #{age}
</if>
</where>
</select>
<!-- set自动添加set关键字,并且移除多余的 逗号-->
<update id="updateUser">
update tb_user
<set>
<if test="age>0">
age = #{age},
</if>
<if test="sex>0">
sex = #{sex},
</if>
<if test="name!=null and name.trim()!=''">
name = #{name}
</if>
</set>
where id = #{id}
</update>
<!--
foreach:遍历集合
collection: 遍历的集合
open:拼接的字符以指定的值开头
close:拼接时以指定的字符结束
separator:拼接时,间隔符
item:集合中被遍历时的变量
-->
<select id="findUsersByIds" resultType="User">
select * from tb_user where id in <!--(#{id},#{id})预编译成(?,?)-->
<foreach collection="ids" open="(" close=")" separator="," item="id" >
#{id}
</foreach>
</select>
<select id="findUserById" resultType="User">
select * from tb_user where id = #{id}
</select>
</mapper>
4.mapper:UserMapper.java
package com.itheima.mapper;
import com.itheima.domain.User;
import org.apache.ibatis.annotations.*;
import java.util.HashMap;
import java.util.List;
public interface UserMapper {
public User findUserById(@Param("id") int id);
//查询男性用户,如果输入了用户名,按用户名模糊查询,如果没有输入用户名,就查询所有男性用户。
public List<User> findUsersByUsername(@Param("username") String username);
// 根据用户名 或者 年龄查询所有男性用户,如果输入了用户名则按照用户名模糊查找,否则就按照年龄查找,
// 两个条件只能成立一个,如果都不输入就查找用户名为“zhangsan”的用户。
public List<User> findUsersByUsernameOrAge(@Param("username") String username,@Param("age") int age);
//查询所有用户,如果输入了用户名按照用户名进行模糊查询,
// 如果输入年龄,按年龄进行查询,如果两者都输入,两个条件都要成立。
public List<User> findUsersByUsernameAndAge(@Param("username") String username,@Param("age") int age);
//修改用户信息,如果参数user中的某个属性为null,则不修改。
public void updateUser(User user);
//根据多个id查询用户的信息
public List<User> findUsersByIds(@Param("ids") List<Integer> ids);
@Select("select * from tb_user where id = #{id}")
public User findUserById2(@Param("id") int id);
@Insert("insert into tb_user(user_name,age) values(#{userName},#{age})")
@Options(useGeneratedKeys = true,keyProperty = "id",keyColumn = "id")
public void addUser(User user);
/**
*
* Results : 注解的作用和<resultMap></resultMap>,声明结果集映射
* Result: 注解的作用和<result><result/> 标签作用一致,配置一组列和属性的映射关系的。
*/
@Results({
@Result(column = "uid",property = "id"),
@Result(column = "uname",property = "userName"),
@Result(column = "uage",property = "age"),
@Result(column = "usex",property = "sex")
})
@Select("select id uid,user_name uname,age uage,sex usex from tb_user where id = #{id}")
public User findUserById3(@Param("id") int id);
}
5.test:UserMapperTest.java
package com.itheima.mapper;
import com.itheima.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import static org.junit.Assert.*;
public class UserMapperTest {
private UserMapper userMapper;
private UserMapper userMapper2;
private SqlSession sqlSession;
private SqlSession sqlSession2;
@Before
public void setUp() throws Exception {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
sqlSession = sqlSessionFactory.openSession(true);
sqlSession2 = sqlSessionFactory.openSession(true);
userMapper = sqlSession.getMapper(UserMapper.class);
userMapper2 = sqlSession2.getMapper(UserMapper.class);
}
@Test
public void findUsersByUsername(){
String username = "%zhang%"; //不为空
List<User> userList = userMapper.findUsersByUsername(username);
for(User user:userList){
System.out.println(user);
}
}
@Test
public void findUsersByUsernameOrAge(){
String username = "%zhang%";
int age = 10;
List<User> userList = userMapper.findUsersByUsernameOrAge(username, age);
for(User user:userList){
System.out.println(user);
}
}
@Test
public void findUsersByUsernameAndAge(){
String username = "%zhang%";
int age = 10;
List<User> userList = userMapper.findUsersByUsernameAndAge(username, age);
for(User user:userList){
System.out.println(user);
}
}
@Test
public void updateUser(){
User user = new User();
user.setId(8l);
user.setName("");
user.setSex(2);
user.setAge(55);
userMapper.updateUser(user);
}
@Test
public void findUsersByIds(){
List<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(2);
ids.add(3);
ids.add(4);
List<User> userList = userMapper.findUsersByIds(ids);
for(User user:userList){
System.out.println(user);
}
}
/**
* mybatis的一级缓存:
* 1.一级缓存无法关闭,一致存在。
* 2.sqlSession.clear()清空缓存
* 3.一级缓存是同一个sqlSession共享。
* 4.任意的增删改都会清空缓存。
*/
@Test
public void testFirstCache(){
System.out.println("第一次查询:");
User user1 = userMapper.findUserById(1);
System.out.println(user1);
User user = new User();
user.setId(8l);
user.setName("");
user.setSex(2);
user.setAge(55);
userMapper.updateUser(user);
//sqlSession.clearCache(); //手动清空缓存
System.out.println("第二次查询:");
User user2 = userMapper2.findUserById(1); //两个userMapper对象也从缓存里查,因为同一个sqlsession
System.out.println(user2); //没有日志输出就是第二次查询
}
/**
* mybatis的二级缓存
* 1.二级缓存需要手动开启 <setting> xxxMapper.xml中 <cache></>
* 2.多个sqlSession共享
* 3.需要调用sqlSession.close()方法来缓存数据
* 4.任意数据的增删改清空缓存,所以还是需要redis
* 5.缓存的实体对象需要实现序列化接口
*/
@Test
public void testSecondCache(){
System.out.println("第一次查询:");
User user = userMapper.findUserById(1);
sqlSession.close();
User user3 = new User();
user3.setId(8l);
user3.setName("");
user3.setSex(2);
user3.setAge(55);
userMapper2.updateUser(user3); //更新8这个用户
System.out.println("第二次查询:");
User user2 = userMapper2.findUserById(1); //查询1这个用户
}
@Test
public void findUserById2(){
User user = userMapper.findUserById2(1);
System.out.println(user);
}
@Test
public void addUser(){
User user = new User();
user.setAge(20);
user.setUserName("aaabbbccc");
userMapper.addUser(user);
System.out.println(user.getId());
}
@Test
public void findUserById3(){
User user = userMapper.findUserById3(1);
System.out.println(user);
}
}
如下是findUsersByUsername函数中String username = " "
如下是findUsersByUsername函数中String username = “%zhang%”
6.OrderMapper.xml:用u,订o,详d,商i
用户和订单:一对多
。订单和商品:多对多
。
<?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.itheima.mapper.OrderMapper">
<!--多表关联查询:1.多表关联情况下的实体设计。 2.多表关联的sql语句。-->
<!--多表查询 包含 订单表信息 和 用户表信息-->
<select id="findOrderAndUserByOrderNumber" resultMap="oneToOne">
select *,u.id uid,o.id oid from tb_user u,tb_order o
where u.id = o.user_id
and o.order_number=#{orderNumber}
</select>
<!-- 定义一对一的结果集映射。单表autoMapping自动开启,嵌套结果集要手动开启 -->
<resultMap id="oneToOne" type="Order" autoMapping="true">
<id column="oid" property="id"></id>
<!-- association一对一的配置
property: 一方的属性即Order的user属性。javaType指定属性类型。
-->
<association property="user" javaType="User" autoMapping="true" >
<id column="uid" property="id"></id>
</association>
</resultMap>
<!--111111111111111111111111111111111111111111111111111111111111111111111111111111111-->
<select id="findOrderAndUserAndOrderDetailsByOrderNumber" resultMap="oneToMany">
select *,u.id uid,o.id oid,d.id did
from tb_user u,
tb_order o,
tb_orderdetail d
where u.id = o.user_id
and o.id = d.order_id
and o.order_number=#{orderNumber}
</select>
<resultMap id="oneToMany" type="Order" autoMapping="true" extends="oneToOne">
<!-- <id column="oid" property="id"></id>
<association property="user" javaType="User" autoMapping="true">
<id column="uid" property="id"></id>
</association>--> <!--用了继承,所以注释-->
<!-- collection一对多映射
property: 多方的属性名
javaType:属性的类型
ofType: 集合的泛型
-->
<collection property="orderdetailList" javaType="List" ofType="OrderDetail" autoMapping="true">
<id column="did" property="id"></id>
</collection>
</resultMap>
<!--1111111111111111111111111111111111111111111111111111111111111111111111111111111111-->
<select id="findOrderAndUserAndOrderDetailsAndItemByOrderNumber" resultMap="manyToMany">
select *,u.id uid,o.id oid,d.id did,i.id iid
from tb_user u,
tb_order o,
tb_orderdetail d,
tb_item i
where
u.id = o.user_id
and o.id = d.order_id
and d.item_id = i.id
and o.order_number = #{orderNumber}
</select>
<!--
多对多查询的本质: 还是一对多的配置,借助中间表实现一对多的关系。
-->
<resultMap id="manyToMany" type="Order" extends="oneToOne" autoMapping="true">
<collection property="orderdetailList" javaType="List" ofType="OrderDetail" autoMapping="true">
<id column="did" property="id"></id>
<association property="item" javaType="Item" autoMapping="true">
<id column="iid" property="id"></id>
</association>
</collection>
</resultMap>
<!--111111111111111111111111111111111111111111111111111111111111111111111111111111111-->
<select id="findOrderLazyUser" resultMap="lazyUser">
select * from tb_order where order_number = #{orderNumber}
</select>
<resultMap id="lazyUser" type="Order" autoMapping="true">
<id property="id" column="id"></id>
<!-- 延迟加载
select : 配置需要执行的sql语句
column: sql语句执行时需要的参数所在的列,即上一条sql执行某一列值
-->
<association property="user" javaType="User" column="user_id" select="com.itheima.mapper.UserMapper.findUserById" autoMapping="true">
<id column="id" property="id"></id> <!--findUserById在UserMapper.xml已写,返回user-->
</association>
</resultMap>
</mapper>
如下order_number和user_id等满足驼峰映射(mybatis-config.xml已开启),自动映射不要配了。如下将uid映射到user对象id属性,oid映射到order对象的id属性。
没有多表查询如下,懒/延时加载用两条sql,分开才有先后顺序。
7.domain:order.java,Orderdetail .java
package com.itheima.domain;
import java.util.List;
public class Order { //订单表
private Integer id;
private Long userId;
private String orderNumber;
private User user; //多变关联情况下实体的设计:可以考虑,将关联的表对应的实体类型作为当前的属性。
private List<Orderdetail> orderdetailList; //订单携带详情,详情里再携带商品
public List<Orderdetail> getOrderdetailList() {
return orderdetailList;
}
public void setOrderdetailList(List<Orderdetail> orderdetailList) {
this.orderdetailList = orderdetailList;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getOrderNumber() {
return orderNumber;
}
public void setOrderNumber(String orderNumber) {
this.orderNumber = orderNumber;
}
@Override
public String toString() { //重新生成有user
return "Order{" +
"id=" + id +
", userId=" + userId +
", orderNumber='" + orderNumber + '\'' +
", user=" + user +
'}';
}
}
package com.itheima.domain;
public class Orderdetail {
private Integer id;
private Double totalPrice;
private Integer status;
private Item item; //携带商品
public Item getItem() {
return item;
}
public void setItem(Item item) {
this.item = item;
}
public Double getTotalPrice() {
return totalPrice;
}
public void setTotalPrice(Double totalPrice) {
this.totalPrice = totalPrice;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Override
public String toString() {
return "Orderdetail{" +
"id=" + id +
", totalPrice=" + totalPrice +
", status=" + status +
", item=" + item +
'}';
}
}
8.mapper:OrderMapper.java
package com.itheima.mapper;
import com.itheima.domain.Order;
import org.apache.ibatis.annotations.Param;
public interface OrderMapper {
//需求:通过订单编号20140921003查询出订单信息,并查询出下单人信息。
public Order findOrderAndUserByOrderNumber(@Param("orderNumber") String orderNumber);
// 需求:通过订单编号20140921001查询订单,并查询出下单人信息以及查询出订单详情。
public Order findOrderAndUserAndOrderDetailsByOrderNumber(@Param("orderNumber") String orderNumber);
//通过订单号20140921001查询订单,查询出下单人信息并且查询出订单详情以及商品数据
public Order findOrderAndUserAndOrderDetailsAndItemByOrderNumber(@Param("orderNumber") String orderNumber);
//延迟加载需求:通过订单编号20140921001查询order并延迟加载user信息
public Order findOrderLazyUser(@Param("orderNumber") String orderNumber);
}
9.test:OrderMapperTest.java
package com.itheima.mapper;
import com.itheima.domain.Order;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import static org.junit.Assert.*;
public class OrderMapperTest {
private OrderMapper orderMapper;
@Before
public void setUp() throws Exception {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
orderMapper = sqlSession.getMapper(OrderMapper.class);
}
@Test
public void findOrderAndUserByOrderNumber() {
Order order = orderMapper.findOrderAndUserByOrderNumber("20140921003");
System.out.println(order);
}
@Test
public void findOrderAndUserAndOrderDetailsByOrderNumber(){
Order order = orderMapper.findOrderAndUserAndOrderDetailsByOrderNumber("20140921001");
System.out.println(order);
System.out.println(order.getOrderdetailList());
}
@Test
public void findOrderAndUserAndOrderDetailsAndItemByOrderNumber(){
Order order = orderMapper.findOrderAndUserAndOrderDetailsAndItemByOrderNumber("20140921001");
System.out.println(order);
System.out.println(order.getOrderdetailList());
}
@Test
public void findOrderLazyUser(){
Order order = orderMapper.findOrderLazyUser("20140921001");
System.out.println(order.getOrderNumber());
System.out.println("开始使用用户的信息了");
System.out.println(order.getUser().getName());
}
}
findOrderAndUserByOrderNumber()执行结果如下。
findOrderAndUserAndOrderDetailsByOrderNumber()执行结果如下。
findOrderAndUserAndOrderDetailsAndItemByOrderNumber()执行结果如下,多个Orderdetail。
findOrderLazyUser执行结果如下,用的时候才去加载。
10.mapper:UserMapper.java,OrderMapper.java,OrderDetailMapper.java,ItemMapper.java
xml配置配的东西多,但是所有配置都在一起。注解虽然配的少,但分布在各个地方。
package com.itheima.mapper;
import com.itheima.domain.User;
import com.itheima.sql.UserSql;
import org.apache.ibatis.annotations.*;
import java.util.HashMap;
import java.util.List;
public interface UserMapper { //注解就不用xxMapper.xml映射文件了
@Select("select * from tb_user where id = #{id}")
public User findUserById2(@Param("id") int id);
//11111111111111111111111111111111111111111111111111111111111111111111111111111111111
@Insert("insert into tb_user(user_name,age) values(#{userName},#{age})")
@Options(useGeneratedKeys = true,keyProperty = "id",keyColumn = "id") //新增主键回显
public void addUser(User user);
//11111111111111111111111111111111111111111111111111111111111111111111111111111111111
/**
* Results : 注解的作用和<resultMap></resultMap>一样,声明结果集映射
* Result: 注解的作用和<result><result/> 标签作用一致,配置一组列和属性的映射关系的
*/
@Results({
@Result(column = "uid",property = "id"),
@Result(column = "uname",property = "userName"),
@Result(column = "uage",property = "age"),
@Result(column = "usex",property = "sex")
})
@Select("select id uid,user_name uname,age uage,sex usex from tb_user where id = #{id}")
public User findUserById3(@Param("id") int id); //如上行自定义别名,无法自动映射,需自定义结果集映射
//1111111111111111111111111111111111111111111111111111111111111111111111111111111111111
/**
* 如果用户名不为空,就按照用户名查询, //动态sql注解开发,下面的第3节
* 如果年龄大于0,就查询年龄大于指定值的用户信息
*/
@SelectProvider(type = UserSql.class,method = "findUsersByCondition")
public List<User> findUsersByConditions(User user);
}
package com.itheima.mapper;
import com.itheima.domain.Order;
import com.itheima.domain.User;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.mapping.FetchType;
import java.util.List;
public interface OrderMapper {
/**
* 注解方式的高级查询的sql语句必须分开写,不支持多表查询。
* 注解一对一
* 通过@One注解来实现的,
* select : 配置需要执行的sql语句
* fetchType: 配置是否启用懒加载
*/
@Results({
@Result(column = "id",property = "id"),
@Result(one=@One(fetchType= FetchType.EAGER ,select = "com.itheima.mapper.UserMapper.findUserById2"),property = "user",javaType = User.class,column = "user_id")
})
@Select("select * from tb_order where order_number=#{orderNumber}")
public Order findOrderAndUserByOrderNumber2(@Param("orderNumber") String orderNumber);
//111111111111111111111111111111111111111111111111111111111111111111111111111111111111
@Results({
@Result(column = "id",property = "id"),
@Result(one=@One(fetchType= FetchType.EAGER ,select = "com.itheima.mapper.UserMapper.findUserById2"),property = "user",javaType = User.class,column = "user_id"),
@Result(many = @Many(select = "com.itheima.mapper.OrderDetailMapper.findOrderDetailsByOid"),property = "orderdetailList",javaType = List.class,column = "id")
})
@Select("select * from tb_order where order_number=#{orderNumber}")
public Order findOrderAndUserAndOrderDetailsByOrderNumber2(@Param("orderNumber") String orderNumber);
//11111111111111111111111111111111111111111111111111111111111111111111111111111111111
@Results({
@Result(column = "id",property = "id"),
@Result(one=@One(fetchType= FetchType.EAGER ,select = "com.itheima.mapper.UserMapper.findUserById2"),property = "user",javaType = User.class,column = "user_id"),
@Result(many = @Many(select = "com.itheima.mapper.OrderDetailMapper.findOrderDetailsByOid"),property = "orderdetailList",javaType = List.class,column = "id")
})
@Select("select * from tb_order where order_number=#{orderNumber}")
public Order findOrderAndUserAndOrderDetailsAndItemByOrderNumber2(@Param("orderNumber") String orderNumber);
}
package com.itheima.mapper;
import com.itheima.domain.Item;
import com.itheima.domain.Orderdetail;
import org.apache.ibatis.annotations.*;
import java.util.List;
public interface OrderDetailMapper {
@Results({
@Result(column = "id",property = "id"),
@Result(property = "item",javaType = Item.class,column = "item_id",
one = @One(select = "com.itheima.mapper.ItemMapper.findItemById"))
})
@Select("select * from tb_orderdetail where order_id = #{oid}")
public List<Orderdetail> findOrderDetailsByOid(@Param("oid") int oid);
}
package com.itheima.mapper;
import com.itheima.domain.Item;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
public interface ItemMapper {
@Select("select * from tb_item where id = #{id}")
public Item findItemById(@Param("id") int id);
}
11.test:UserMapperTest.java,OrderMapperTest.java
package com.itheima.mapper;
import com.itheima.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import static org.junit.Assert.*;
public class UserMapperTest {
private UserMapper userMapper;
private UserMapper userMapper2;
private SqlSession sqlSession;
private SqlSession sqlSession2;
@Before
public void setUp() throws Exception {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
sqlSession = sqlSessionFactory.openSession(true);
sqlSession2 = sqlSessionFactory.openSession(true);
userMapper = sqlSession.getMapper(UserMapper.class);
userMapper2 = sqlSession2.getMapper(UserMapper.class);
}
@Test
public void findUserById2(){
User user = userMapper.findUserById2(1);
System.out.println(user);
}
@Test
public void addUser(){
User user = new User();
user.setAge(20);
user.setUserName("aaabbbccc");
userMapper.addUser(user);
System.out.println(user.getId());
}
@Test
public void findUserById3(){
User user = userMapper.findUserById3(1);
System.out.println(user);
}
@Test
public void findUsersByConditions(){
User user = new User();
user.setUserName("%zhang%");
user.setAge(15);
List<User> userList = userMapper.findUsersByConditions(user);
for(User user1:userList){
System.out.println(user1);
}
}
}
findUsersByConditions执行结果:
package com.itheima.mapper;
import com.itheima.domain.Order;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import static org.junit.Assert.*;
public class OrderMapperTest {
private OrderMapper orderMapper;
@Before
public void setUp() throws Exception {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
orderMapper = sqlSession.getMapper(OrderMapper.class);
}
@Test
public void findOrderAndUserByOrderNumber() {
Order order = orderMapper.findOrderAndUserByOrderNumber("20140921003");
System.out.println(order);
}
@Test
public void findOrderAndUserAndOrderDetailsByOrderNumber(){
Order order = orderMapper.findOrderAndUserAndOrderDetailsByOrderNumber("20140921001");
System.out.println(order);
System.out.println(order.getOrderdetailList());
}
@Test
public void findOrderAndUserAndOrderDetailsAndItemByOrderNumber(){
Order order = orderMapper.findOrderAndUserAndOrderDetailsAndItemByOrderNumber("20140921001");
System.out.println(order);
System.out.println(order.getOrderdetailList());
}
@Test
public void findOrderLazyUser(){
Order order = orderMapper.findOrderLazyUser("20140921001");
System.out.println(order.getOrderNumber());
System.out.println("开始使用用户的信息了");
System.out.println(order.getUser().getName());
}
@Test
public void findOrderAndUserByOrderNumber2(){
Order order = orderMapper.findOrderAndUserByOrderNumber2("20140921003");
System.out.println(order.getOrderNumber());
System.out.println("懒加载用户信息:");
System.out.println(order.getUser().getName());
}
@Test
public void findOrderAndUserAndOrderDetailsByOrderNumber2(){
Order order = orderMapper.findOrderAndUserAndOrderDetailsByOrderNumber2("20140921001");
System.out.println(order);
System.out.println(order.getOrderdetailList());
}
@Test
public void findOrderAndUserAndOrderDetailsAndItemByOrderNumber2(){
Order order = orderMapper.findOrderAndUserAndOrderDetailsAndItemByOrderNumber2("20140921001");
System.out.println(order);
System.out.println(order.getOrderdetailList());
}
}
findOrderAndUserByOrderNumber执行结果:
findOrderAndUserAndOrderDetailsByOrderNumber执行结果:
findOrderAndUserAndOrderDetailsAndItemByOrderNumber2执行结果:
12.动态sql注解开发
package com.itheima.sql;
import com.itheima.domain.User;
public class UserSql {
public String findUsersByCondition(User user){
StringBuffer sb = new StringBuffer("select * from tb_user where 1=1 ");
if(user.getUserName()!=null&&user.getUserName().trim()!=""){
sb.append(" and user_name like #{userName} ");
}
if(user.getAge()>0){
sb.append(" and age>#{age} ");
}
return sb.toString();
}
}