Spring对于赋值Xml赋值方式

本文详细介绍了Spring框架中各种数据类型的绑定方法,包括基本数据类型、自定义数据类型、引用数据类型及构造器注入等。通过具体的XML配置示例和测试代码,展示了不同场景下数据绑定的应用。

1.1. Spring的数据的赋值

1.1.1. 对于基本数据类型的赋值

 <bean id="student" class="com.bjsxt.lc.spring.pojo.AStudent" scope="singleton">

 <property name="id" value="01"/>

 <property name="name"><value>测试</value></property>

 <property name="price" value="2.2"/>

 </bean>

总结:优两种方式:

l 在property的标签里利用value标签

l 在property标签里加入value标签进行赋值

1.1.2. 对于自定义数据类型的赋值

方法一:

<property name="clazz">

 <!-- <bean id="clazz" class="com.bjsxt.lc.spring.pojo.AClazz">

 <property name="id" value="001"/>

 <property name="name" value="教室2"/>

 </bean> -->

 </property>

 

方法二:

 

<property name="clazz" ref="clazz"/>

 <bean id="clazz" class="com.bjsxt.lc.spring.pojo.AClazz">

 <property name="id" value="001"/>

 <property name="name" value="教室2"/>

 </bean>

总结

l 方法一:更多的是以一种内部类的形式赋值

l 方法二:是做了一个类与类之间的关联

1.1.3. 引用型数据类型的赋值

<!-- 测试list -->

 <property name="hobbysList">

 <list>

 <value>List测试数据一</value>

 <value>List测试数据二</value>

 <value>List测试数据三</value>

 </list>

 </property>

 <!-- 测试set容器 -->

 <property name="hobbysSet">

 <set>

 <value>set测试数据一</value>

 <value>set测试数据二</value>

 <value>set测试数据三</value>

 </set>

 </property>

 <!-- 测试Map容器 -->

 <property name="hobbysMap">

 <map>

 <entry key="a" value="a_"/>

 <entry key="b" value="b_"/>

 <entry key="c" value="c_"/>

 </map>

 </property>

 <!-- 测试数组 -->

 <property name="hobbys">

 <array>

 <value>测试数据1</value>

 <value>测试数据2</value>

 <value>测试数据3</value>

 </array>

 </property>

 <!--

 测试 List里面放对象

 不可以在list里面继续放value,然后value里面在bean一个对象

 -->

 <property name="clazzList">

 <list>

<ref bean="clazz"/>

<ref bean="clazz2"/>

 </list>

 </property>

 <!-- properties测试 -->

 <property name="properties">

 <props>

 <prop key="a1">properties测试数据一</prop>

 <prop key="a2">properties测试数据2</prop>

 </props>

 </property>

 </bean>

 

 <bean id="clazz" class="com.bjsxt.lc.spring.pojo.AClazz">

 <property name="id" value="001"/>

 <property name="name" value="教室2"/>

 </bean>

 <bean id="clazz2" class="com.bjsxt.lc.spring.pojo.AClazz">

 <property name="id" value="002"/>

 <property name="name" value="教室3"/>

 </bean>

测试代码:

package com.bjsxt.lc.spring.test;

 

import java.util.Arrays;

 

import org.junit.Test;

 

import com.bjsxt.lc.spring.pojo.AStudent;

 

public class TestFile extends TestFiledInfo

{

@Test

public void testFile()

{

AStudent stu = (AStudent) this.applicationContext.getBean("student");

logger.info("----学生id:{},学生姓名:{},学生学费{}===>", stu.getId(), stu.getName(), stu.getPrice());

logger.info("====学生班级信息:{}", stu.getClazz());

//测试list

logger.info("----list测试-----》{}", stu.getHobbysList());

// set容器不容许值重复

logger.info("----set测试数据---->{}", stu.getHobbysSet());

// 测试Map容器

logger.info("----map容器测试数据---》{}", stu.getHobbysMap());

// 测试clazz'List

logger.info("----clazzList容器测试数据---》{}", stu.getClazzList());

// 测试properties

logger.info("----properties容器测试数据---》{}", stu.getProperties());

//数组

logger.info("-----数组测试----》{}",Arrays.toString(stu.getHobbys()));

logger.info("-----数组测试----》{}",stu.getHobbys());

}

}

 

 

1.1.4. 构造器赋值

注:构造器赋值,必须在实体类中提供构造器

 

 <bean id="clazz3" class="com.bjsxt.lc.spring.pojo.AClazz">

<!--  <constructor-arg index="0" value="10"/>

 <constructor-arg index="1" value="张三"/> -->

 <constructor-arg name="id" value="10"/>

 <constructor-arg name="name" value="张三"/>

 </bean>

测试代码

 

@Test

public void testCons()

{

AClazz clazz = (AClazz) this.applicationContext.getBean("clazz3");

logger.info("===测试对象==={}",clazz);

}

 

 

注:测试代码的父类:

 

 
  1. package com.bjsxt.lc.spring.test;

  2.  
  3. import org.apache.logging.log4j.LogManager;

  4. import org.apache.logging.log4j.Logger;

  5. import org.junit.Before;

  6. import org.junit.Test;

  7. import org.springframework.context.ApplicationContext;

  8. import org.springframework.context.support.ClassPathXmlApplicationContext;

  9.  
  10. public class TestFiledInfo

  11. {

  12. protected Logger logger = LogManager.getLogger(TestFiledInfo.class);

  13.  
  14. protected ApplicationContext applicationContext = null;

  15. @Before

  16. public void infoSpring()

 

{applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");logger.info("---infoSpring--");}}
 
 

 

最后测试结果

 

 
[plain] view plain copy
  1. <code class="language-java">2016-11-11 21:02:29,787 INFO  [main] test.TestFiledInfo (TestFiledInfo.java:19) - ---infoSpring--  
  2. 2016-11-11 21:02:29,796 INFO  [main] test.TestFile (TestFile.java:16) - ----学生id:1,学生姓名:张三,学生学费2.2===>  
  3. 2016-11-11 21:02:29,799 INFO  [main] test.TestFile (TestFile.java:17) - ====学生班级信息:AClazz [id=1, name=教室2]  
  4. 2016-11-11 21:02:29,799 INFO  [main] test.TestFile (TestFile.java:19) - ----list测试-----》[List测试数据一, List测试数据二, List测试数据三]  
  5. 2016-11-11 21:02:29,800 INFO  [main] test.TestFile (TestFile.java:21) - ----set测试数据---->[set测试数据一, set测试数据二, set测试数据三]  
  6. 2016-11-11 21:02:29,801 INFO  [main] test.TestFile (TestFile.java:23) - ----map容器测试数据---》{a=a_, b=b_, c=c_}  
  7. 2016-11-11 21:02:29,801 INFO  [main] test.TestFile (TestFile.java:25) - ----clazzList容器测试数据---》[AClazz [id=1, name=教室2], AClazz [id=2, name=教室3]]  
  8. 2016-11-11 21:02:29,801 INFO  [main] test.TestFile (TestFile.java:27) - ----properties容器测试数据---》{a2=properties测试数据2, a1=properties测试数据一}  
  9. 2016-11-11 21:02:29,802 INFO  [main] test.TestFile (TestFile.java:29) - -----数组测试----》[测试数据1, 测试数据2, 测试数据3]  
  10. 2016-11-11 21:02:29,802 INFO  [main] test.TestFile (TestFile.java:30) - -----数组测试----》测试数据1</code>  
在使用 **MyBatis** 时,如果你发现给 Spring 管理的 Entity 字段赋值为 `null` 后执行更新操作,数据库字段 **没有被更新为 NULL**,这是非常常见的问题。这与 MyBatis 的默认行为和 SQL 生成机制有关。 --- ## ✅ 核心原因:MyBatis 不会自动将 null 值写入数据库(除非显式指定) MyBatis 在生成动态 SQL 时(尤其是配合 `<set>` 和 `#{}` 使用),**如果某个字段值为 `null`,它会在 `SET` 子句中直接跳过该字段**,导致该字段不会被更新 —— 即使你希望把它设成 `NULL`。 --- ### 🔍 示例说明 假设你有如下实体和 Mapper: ```java public class User { private Long id; private String name; private Integer age; // getter/setter } ``` Mapper 接口: ```java void updateUser(User user); ``` XML 映射文件: ```xml <update id="updateUser"> UPDATE user <set> <if test="name != null">name = #{name},</if> <if test="age != null">age = #{age},</if> </set> WHERE id = #{id} </update> ``` #### ❌ 问题出现: 当你调用: ```java User user = new User(); user.setId(1L); user.setName("John"); user.setAge(null); // 想把 age 更新为 NULL userMapper.updateUser(user); ``` 生成的 SQL 是: ```sql UPDATE user SET name = 'John' WHERE id = 1 ``` 👉 `age` 字段根本没出现在 `SET` 中,所以 **数据库中的 `age` 值保持不变**,而不是变为 `NULL`! --- ## ✅ 解决方案 ### ✅ 方案一:修改 `<if>` 判断逻辑,允许更新 null(推荐) 如果你想让 `null` 值也能更新到数据库,就不要用 `<if test="xxx != null">` 来包裹字段。 #### ✔️ 修改 XML 为: ```xml <update id="updateUser"> UPDATE user <set> name = #{name}, age = #{age} </set> WHERE id = #{id} </update> ``` 这样无论 `name` 或 `age` 是否为 `null`,都会出现在 `SET` 中,MyBatis 会将其作为 `NULL` 写入数据库。 > ⚠️ 注意:这种方式要求你传入的对象中每个字段都“有意图”,否则可能误更新。 --- ### ✅ 方案二:使用 `test="property != null or property == null"` 强制包含 null 如果你只想对特定字段支持 `null` 更新,可以这样写: ```xml <update id="updateUser"> UPDATE user <set> <if test="name != null">name = #{name},</if> <!-- 强制更新 age,即使为 null --> age = #{age}, </set> WHERE id = #{id} </update> ``` 或者更灵活地控制: ```xml <if test="age != null or age == null">age = #{age},</if> ``` 但这等价于始终包含,不如直接写出来。 --- ### ✅ 方案三:使用 `@Param` + 动态判断业务意图 有时候你不希望所有 null 都更新,而是根据前端是否传递了这个字段来决定。 这时可以用 DTO 包装,并使用 `java.util.Optional` 或自定义包装类(如 `UpdateField<T>`)。 但更简单的方式是使用 Map: ```java @Update({ "<script>", "UPDATE user", "<set>", " <if test='name != null'>name = #{name},</if>", " <if test='age != \"\"'>age = #{age},</if>", <!-- 特殊处理 --> "</set>", "WHERE id = #{id}", "</script>" }) void updateUser(@Param("params") Map<String, Object> params); ``` 然后调用时只放入你想更新的字段。 --- ### ✅ 方案四:使用 `insertSelective` / `updateSelective` 思想反向思考 很多开发者误以为“不更新 null”是优点,其实是双刃剑。 你可以考虑: - 提供两个方法: - `updateSelective(User user)`:跳过 null - `updateWithNull(User user)`:强制更新所有字段 ```xml <!-- 跳过 null --> <update id="updateSelective"> UPDATE user <set> <if test="name != null">name = #{name},</if> <if test="age != null">age = #{age},</if> </set> WHERE id = #{id} </update> <!-- 强制更新 --> <update id="updateWithNull"> UPDATE user SET name = #{name}, age = #{age} WHERE id = #{id} </update> ``` 按需调用即可。 --- ## ✅ 补充建议 ### 1. 使用注解方式也一样受 XML 控制影响 即使你用注解: ```java @Update("UPDATE user SET name=#{name}, age=#{age} WHERE id=#{id}") void updateUser(User user); ``` 只要字段为 `null`,MyBatis 仍然会将其作为 `NULL` 传给 JDBC —— 所以这是可以正常工作的! 👉 所以:**关键在于你的 SQL 是否包含了那个字段**。 --- ### 2. 数据库字段允许 NULL? 确保数据库字段本身允许 `NULL`,否则会报错: ```sql ALTER TABLE user MODIFY COLUMN age INT NULL; ``` --- ### 3. 开启日志查看实际执行 SQL ```yaml # application.yml logging: level: com.example.mapper: debug # 替换为你的 mapper 包路径 ``` 或: ```properties logging.level.com.yourpackage.UserMapper=DEBUG ``` 你会看到类似: ``` ==> Preparing: UPDATE user SET name = ?, age = ? WHERE id = ? ==> Parameters: John(String), null, 1(Long) ``` 如果有 `null` 参数并成功绑定,就会写入数据库。 --- ## ✅ 总结对比表 | 方法 | 是否支持 null 更新 | 说明 | |------|------------------|------| | `<if test="field != null">` | ❌ | 跳过 null 字段 | | 直接写 `field = #{field}` | ✅ | 支持 null 写入 | | 使用 Map + 动态判断 | ✅ | 更灵活控制更新意图 | | 注解 SQL + #{field} | ✅ | 只要写了字段,null 也会更新 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值