小蔡学Java

MyBatis(二):配置及动态SQL

2023-05-13 15:35 1277 0 SSM / SpringBoot 框架篇 MybatisMySQL

四、配置:

  • mybatis的settings配置很丰富:

  • Mybatis默认支持别名:

  • 自定义别名:

  • 使用Mapper代理的形式开发,需要编写Mapper接口

    • 要么使用@Mapper接口标注在每一个Mapper接口上。

    • 要么在启动类上使用@MapperScan(basePackages = "com.whitecamellia.mapper")进行全包扫描。

  • 编写Mapper接口对应的xml映射文件。注意:映射文件目录要与Mapper接口包对应

  • 可以在启动类上添加注解,来批量扫描Mapper接口,从而避免使用@Mapper注解

@SpringBootApplication
@MapperScan(basePackages = "com.whitecamellia.mapper")
public class MybatisDemoApplication {
 
    public static void main(String[] args) {
 
        SpringApplication.run(MybatisDemoApplication.class, args);
    }
 
}
  • Spring Boot项目默认使用logback作为日志框架,可以设置日志等级来输出更多信息,比如Mybatis所执行的SQL
logging.level.com.whitecamellia.mybatis_demo=debug
  • Spring Boot项目指定映射文件路径(指定resource根目录下mapper中的所有Mapper.xml文件)
mybatis.mapper-locations=classpath:mapper/*Mapper.xml

Mybatis中的配置都可以在application.properties中完成,包括数据库连接池的配置、驼峰配置、别名配置等。

# 下划线转驼峰 
mybatis.configuration.map-underscore-to-camel-case=true
<select id="findAll" resultType="com.whitecamellia.entity.Person">
        select *
        from person
 </select>
// 可以不必再指定resultMap
# 别名
mybatis.type-aliases-package=com.whitecamellia.entity
<select id="findAll" resultType="person">
        select *
        from person
 </select>
- 主键返回(useGeneratedKeys)

mybatis.configuration.use-generated-keys=true
public class Cat {
    private String id;
    private String name;
    private Integer pId;
 
   getter&&setter
 
}
<!--   personMapper-->
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
        insert into person (id, name, age, love_color)
        values (null, #{name}, #{age}, #{loveColor})
  </insert>
public interface CatMapper {
    int insert(Cat cat);
}
<!--    catMapper-->
  <insert id="insert">
        insert into cat (id, name, p_id)
        values (#{id}, #{name}, #{pId})
 </insert>
 @Test
    void insertCat() {
        Person person = new Person();
        person.setId(null);
        person.setName("王一猫");
        person.setAge(20);
        person.setLoveColor("黄色");
        personMapper.insert(person);
        Cat cat = new Cat();
        cat.setId(null);
        cat.setName("大黄");
        cat.setpId(person.getId());
        catMapper.insert(cat);
    }

五. 动态SQL

  • 什么是动态sql Mybatis可以通过语法的判断对sql进行灵活封装,拼接。

  • 需求:

    • 没有条件,select * from person

    • 查询id=1的姓名 select * from person where id = 1

    • 查询name=zs的姓名 select * from person where name = ‘’zs“

    • 查询id=1的并age=23的。select * from person where id = 1 and age = 23

    • 会发现我们需要写很多种可能的sql语句。不灵活

    • 动态sql就是解决这个问题的。

  • if标签和where标签

		<select id="find" resultType="com.whitecamellia.entity.Person">
				select *
				from person
				<where>
					<if test="id!=null">
						and id = #{id}
					</if>
					<if test="name!=null and name != ''">
						and name = #{name}
					</if>
					<if test="age!=null">
						and age = #{age}
					</if>
					<if test="loveColor!=null">
						and love_color liKe "%"#{loveColor}"%"
					</if>
				</where>
			</select>
  • 注意:
  • 1.like这块 的字符拼接如下两种方式都可以,
  • and love_color liKe "%"#{loveColor}"%" 推荐使用这种方式
  • and love_color liKe "%${loveColor}%" 但是$的形式,是字符串拼接的,会出现sql注入问题。
  • 2.注释使用xml的注释,不能使用sql语句注释
	public interface PersonMapper {
	 ...
		 List<Person> find(Person person);
	...
	}

测试:

		PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);

		//我们可以选择性的按照条件查询可以根据id或者name,或者color
		Person person = new Person();
		//person.setId(1);
		person.setName("张三");
		person.setLovecolor("红色");
		List<Person> byColor = mapper.findByColor(person);
		System.out.println(byColor);
	}

	  @Test
		void find() {
		   //我们可以选择性的按照条件查询可以根据id或者name,或者color
			Person person = new Person();
			person.setId(1);
			person.setName("李四");
			person.setLoveColor("色");
			List<Person> persons = personMapper.find(person);
			for (Person human : persons) {
				System.out.println(human);
			}
		}
  • sql片段 sql片段可以让程序员写的sql使用率更高,也就是说可重用性更高。
		可以用sql标签定义一些必须查询列,提取出来。然后用include标签引入
		<sql id="all">
				id
				,name,age
		</sql>

		<select id="findAll" resultMap="personMap">
				select
				<include refid="all"/>
				,love_color
				from person
		 </select>

  • foreach标签

删除:delete

	写法一:
	<delete id="deleteByIds">

				<!-- collection:指定输入集合或者数组的参数名称 集合就是list。数组就是array -->
				<!-- item:声明遍历出的参数变量 -->
				<!-- open:遍历开始时需要拼接的内容 -->
				<!-- close:遍历结束时需要拼接的内容 -->
				<!-- separator:遍历出的参数变量之间需要拼接的参数 ,delete from person where id in ( 1,2,3)-->
			delete from person where id in (
			<foreach collection="array" item="deleteid" separator=",">
				${deleteid}
			</foreach>
			)
		</delete>

	写法二:
	<delete id="deleteByIds">
			delete from person
			<foreach collection="array" item="deleteid" open="where id in (" close=")" separator=",">
				${deleteid}
			</foreach>
		</delete>

	混合判断:delete from person where id in (1,2)
	<delete id="deleteByIds">
		delete from person
		<where>
			<if test="list!=null and list.size>0">
				<foreach collection="list" item="id" open="and id in ( " close=" ) " separator=",">
					#{id}
				</foreach>
			</if>
			<if test="list==null or list.size==0">
				and 1d = 2
			</if>
		</ where>
	</delete>

	public interface PersonMapper {
		  //批量删除  根据ids批量删除数据
		  public int deleteByIds(Integer[] ids);
	  }
  • set标签

相当于update的set关键字,会帮我们去掉最后一个逗号

更新:update

	<update id="update">
			update person
			<set>
				<if test="person.name!=null">
					name = #{person.name},
				</if>
				<if test="person.age!=null">
					age = #{person.age},
				</if>
				<if test="person.loveColor!=null">
					love_color = #{person.loveColor},
				</if>
			</set>
			where id = #{id}

		</update>
	 @Test
		void updateById() {
			Person person = new Person();
			person.setName("小红");
			person.setAge(20);
			person.setLoveColor("红色");
			personMapper.update(2, person);
		}
	public interface PersonMapper {
		  //根据id 修改信息
		  int update(int id, Person person);
	  }

传递多个参数问题

	<update id = "update">
	  update person 
	  <set>
			<if test="person.name!=null">
		  name = #{person.name},
			<if test="person.age!=null">
		  name = #{person.age},
		  <if test="person.loveColor!=null">
		  love_color = #{person.loveColor},
	  </set>
	  where id = #{id}
	</update>

六、 多表映射

需求一

需求:查询订单信息,关联查询购买该订单的用户信息。

需求:查询订单信息,关联查询购买该订单的用户信息。

sql:

	SELECT * FROM `order` o, `user` u WHERE o.user_id = u.id;

多表查询涉及到重名的字段,可以通过sql中的别名解决:

  • 需求:查询订单信息,关联查询购买该订单的用户信息。
	SELECT
		o.id order_id,
		o.create_time create_time,
		o.user_id user_id,
		u.username username,
		u.PASSWORD PASSWORD 
	FROM
		`order` o,
		`user` u 
	WHERE
		o.user_id = u.id

  • 需求:查询订单信息,关联查询购买该订单的用户信息。
	SELECT 
	o.id order_id,
	o.create_time create_time,
	o.user_id  user_id,
	u.username username,
	u.`password` `password`
	FROM 
	`order` o
	LEFT JOIN `user`  u
	ON o.user_id = u.id

查询出正确且合适的结果集后,就可以进行映射的配置了:

User类。用户信息

	public class User {
		private Integer id;
		private String username;
		private String password;
			//getter setter
	}

Order类。订单

	public class Order {
		private Integer id;
		private Date createTime;
		private Integer userId;
		//private User user;//后加 代表订单所属用户
			//getter setter
	}

	//  在多对一的时候,我们通常将一的一方作为多的一方的属性
	//  这样是为了保证下方的List集合的泛型

创建OderMapper接口和OrderMapper.xml

	public interface OrderMapper {
		List<Order> findOrdersWithUser();
	}
	//  这里泛型定义成Order是因为我们将User的相关信息定义成了Order类的属性。
	//  在多对一的时候,我们通常将一的一方作为多的一方的属性

	<resultMap id="findOrdersWithUser" type="com.whitecamellia.entity.Order" autoMapping="true">
			<id column="order_id" property="id"/>
			<result column="create_time" property="createTime"/>
			<result column="user_id" property="userId"/>
			<association property="user" javaType="User" autoMapping="true">
				<id column="user_id" property="id"/>
				<result column="username" property="username"/>
				<result column="password" property="password"/>
			</association>

		</resultMap>

		<select id="findOrdersWithUser" resultMap="findOrdersWithUser">
			SELECT o.id          order_id,
				   o.create_time create_time,
				   o.user_id     user_id,
				   u.username    username,
				   u.`password`  `password`
			FROM `order` o
					 LEFT JOIN `user` u
							   ON o.user_id = u.id
		</select>

代表单一的关联,在多对一 或 一对一的关系中使用,注意需要指定javaType属性。

测试类:

	 @Autowired
	 private OrderMapper orderMapper; 
	@Test
		void findOrdersWithUser() {
			List<Order> ordersWithUser = orderMapper.findOrdersWithUser();
			for (Order order : ordersWithUser) {
				System.out.println(order);
			}
		}

注意:

我们想偷个懒,标注红线的地方的映射我们想省略,

# 下划线转驼峰
mybatis.configuration.map-underscore-to-camel-case=true

此外:我们还有另外一种做法:这里我们需要引入一个新的概念DTO

**数据传输对象(DTO)(Data Transfer Object),是一种设计模式之间传输数据的软件应用系统。**数据传输目标往往是数据访问对象从数据库中检索数据。数据传输对象与数据交互对象或数据访问对象之间的差异是一个以不具有任何行为除了存储和检索的数据(访问和存取器)。

  • 新建包dto,并创建 OrderAndUserDTO dto
		public class OrderAndUserDTO {
		private Integer orderId;
		private Date createTime;
		private Integer userId;
		private String username;
		private String password;
	   // getter && sertter..
	}
  • 在接口OrderMapper添加新方法
		public interface OrderAndUserDtoMapper {
		List<OrderAndUserDTO> findOrderAndUser();
		}

  • OrderMapper.xml中增加如下配置
		<resultMap id="findOrderAndUser" type="com.whitecamellia.dto.OrderAndUserDto" autoMapping="true">
				<id column="order_id" property="orderId"/>
			</resultMap>
			<select id="findOrderAndUser" resultMap="findOrderAndUser">
				SELECT o.id          order_id,
					   o.create_time create_time,
					   o.user_id     user_id,
					   u.username    username,
					   u.`password`  `password`
				FROM `order` o
						 LEFT JOIN `user` u
								   ON o.user_id = u.id
			</select>
  • 测试
		   @Autowired
			private OrderMapper orderMapper;

		@Test
			void findOrderAndUser() {
				List<OrderAndUserDto> ordersWithUser = orderMapper.findOrderAndUser();
				for (OrderAndUserDto orderAndUserDto : ordersWithUser) {
					System.out.println(orderAndUserDto);
				}
			}

需求二

需求:查询订单信息,关联查询它的订单明细信息。

sql:

	SELECT * FROM`order` o,order_item oi WHERE o.id = oi.order_id

整理之后的sql语句:

	SELECT
		o.id  order_id,
		o.create_time create_time,
		o.user_id user_id,
		oi.id order_item_id,
		oi.item_id item_id,
		oi.num num
	FROM
		`order` o,
		order_item oi
	WHERE 
		o.id = oi.order_id

Order类

	public class Order {
		private Integer id;
		private Date createTime;
		private Integer userId;
		private User user; // 代表订单所属用户
		private List<OrderItem> orderItems;//代表订单明细信息
		//getter setter toString
	}

OrderItem 类

	public class OrderItem {
		private Integer id;
		private Integer orderId;
		private Integer itemId;
		private Integer num;
		// getter&&setter&& toString
	}
//lombok 为我们提供getter&&setter&&toString

OrderMapper接口添加新方法

	public interface OrderMapper {
		....
	   List<Order> findOrdersWithOrderItems();

	}

OrderMapper.xml映射文件配置

	<resultMap id="OrdersWithOrderItemsMap" type="order" autoMapping="true">
			<id column="order_id" property="id"/>
			<result column="create_time" property="createTime"/>
			<result column="user_id" property="userId"/>
			<collection property="orderItems" ofType="OrderItem" autoMapping="true">
				<id column="order_item_id" property="id"/>
				<result column="order_id" property="orderId"/>
				<result column="item_id" property="itemId"/>
				<result column="num" property="num"/>
			</collection>


		</resultMap>

		<select id="findOrdersWithOrderItems" resultMap="OrdersWithOrderItemsMap">
			SELECT o.id          order_id,
				   o.create_time create_time,
				   o.user_id     user_id,
				   oi.id         order_item_id,
				   oi.item_id    item_id,
				   oi.num        num
			FROM `order` o,
				 order_item oi
			WHERE o.id = oi.order_id
		</select>

测试:

	 @Test
		void findOrdersWithOrderItems() {
			List<Order> ordersWithOrderItems = orderMapper.findOrdersWithOrderItems();
			for (Order ordersWithOrderItem : ordersWithOrderItems) {
				System.out.println(ordersWithOrderItem);
		  }

<collection>代表集合的关联,在一对多的关系中使用,注意需要通过ofType属性指定集合泛型的类型。

dto写法:

创建 OrdersAndOrderItemsDto 类

	@Data
	public class OrdersAndOrderItemsDto {
		private Integer orderId;
		private Date createTime;
		private Integer userId;
		private Integer orderItemId;
		private Integer itemId;
		private Integer num;

	}

OrderMapper.xml文件配置

	 <resultMap id="OrdersAndOrderItemsMap" type="OrdersAndOrderItemsDto" autoMapping="true">
			<id column="order_id" property="orderId"/>
		</resultMap>

		<select id="findOrdersAndOrderItems" resultMap="OrdersAndOrderItemsMap">
			SELECT o.id          order_id,
				   o.create_time create_time,
				   o.user_id     user_id,
				   oi.id         order_item_id,
				   oi.item_id    item_id,
				   oi.num        num
			FROM `order` o,
				 order_item oi
			WHERE o.id = oi.order_id
		</select>

测试

	List<OrdersAndOrderItemsDto> ordersAndOrderItems = mapper.findOrdersAndOrderItems();
			for (OrdersAndOrderItemsDto ordersAndOrderItem : ordersAndOrderItems) {
			System.out.println(ordersAndOrderItem);
		}
  • 代表集合的关联,在一对多的关系中使用,注意需要通过ofType属性指定集合泛型的类型。

dto写法:

创建 OrdersAndOrderItemsDto 类

@Data
public class OrdersAndOrderItemsDto {
    private Integer orderId;
    private Date createTime;
    private Integer userId;
    private Integer orderItemId;
    private Integer itemId;
    private Integer num;
 
}

OrderMapper.xml文件配置


 <resultMap id="OrdersAndOrderItemsMap" type="OrdersAndOrderItemsDto" autoMapping="true">
        <id column="order_id" property="orderId"/>
    </resultMap>
 
    <select id="findOrdersAndOrderItems" resultMap="OrdersAndOrderItemsMap">
        SELECT o.id          order_id,
               o.create_time create_time,
               o.user_id     user_id,
               oi.id         order_item_id,
               oi.item_id    item_id,
               oi.num        num
        FROM `order` o,
             order_item oi
        WHERE o.id = oi.order_id
    </select>

测试

List<OrdersAndOrderItemsDto> ordersAndOrderItems = mapper.findOrdersAndOrderItems();
        for (OrdersAndOrderItemsDto ordersAndOrderItem : ordersAndOrderItems) {
        System.out.println(ordersAndOrderItem);
    }

评论( 0 )

  • 博主 Mr Cai
  • 坐标 河南 信阳
  • 标签 Java、SpringBoot、消息中间件、Web、Code爱好者

文章目录