通用Mapper简单使用

一、Java实体类:
考虑到基本数据类型在Java类中都有默认值,会导致Mybatis在执行相关
操作的时候很难判断当前字段是否为null,所以在Mybatis环境下使用java
实体类的时候尽量不要使用基本数据类型,都使用对应的包装类型。

二、加入Maven依赖:

<!-- 通用Mapper -->
<dependency>
	<groupId>tk.mybatis</groupId>
	<artifactId>mapper</artifactId>
	<version>4.0.0-bate3</version>
</dependency>

三、修改spring配置文件:

<!-- 扫描dao接口 -->
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.company.dao"/>
</bean>

改为

<!-- 扫描dao接口 -->
<bean id="mapperScanner" class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.company.dao"/>
</bean>

默认是采用mysql数据库,其他数据库需要配置 

四、dao文件:

import tk.mybatis.mapper.common.Mapper;

/**
 * 具体操作数据库的Mapper接口,需要继承通用Mapper提供的核心接口 Mapper<T>
 * 泛型类型为操作的数据库表对应的实体类
 */
public interface EmployeeDao extends Mapper<Employee> {

}

五、常用注解:

1.@Table注解
	作用:当表名和实体类名不一致时,建立实体类和数据库表之间的对应关系
	默认规则:实体类类名首字母小写作为表名。Employee类 ---> employee表
	用法:在@Table注解的name属性中指定目标数据库表的表名
	
	@Table(name="tabple_emp")
	public class Employee{
		private Integer empId;
		private String empName;
		private Double empSalary;
	}
	
2.@Column注解
	作用:建立实体类字段和数据库表字段之间的对应关系
	默认规则:
		实体类字段名:驼峰式命名,例如 empId
		数据库表字段:使用"_"区分各个单词命名,例如 emp_id
	用法:在@Column注解的name属性中指定目标数据库表的字段名
	
	@Column(name="emp_salary_apple")
	private Double empSalary;  // 数据库表中字段名为 emp_salary_apple
	
3.@Id注解
	通用Mapper在执行 xxxByPrimaryKey(key)方法时,有两种情况:
	情况1:没有使用@Id注解指定主键字段
		会报错,它会将实体类中所有的字段集合起来,作为联合主键
	情况2:使用@Id注解明确标记和数据库中主键字段对应的实体类属性
	
4.@Transient注解
	一般情况下,实体类中的字段和数据库表中字段是一一对应的,但是也有很多情况下会在实体类中
	增加一些额外的属性,这种情况下就需要使用@Transient注解来告诉通用Mapper这不是表中字段。
	
5.@GeneratedValue
	作用:让通用Mapper在执行insert操作之后将数据库自动生成的主键值回写到实体类对象中。
	
	自增主键用法:
	
		Employee employee= new Employee(null,"cat",6666.66,null);
		employeeService.insert(employee); // dao调用insert
		
		//一般情况下返回null
		//如果empId为自增的主键,并且在实体类的 empId 属性上添加了 @Id 和 @GeneratedValue(strategy=GeneratedType.IDENTITY)
		Integer empId = employee.getEmpId();
	
	序列主键用法:
	
		//如果是Oracle
		@Id
		@GeneratedValue(
			strategy=GeneratedType.IDENTITY,
			generator="select SEQ_ID.nextval from dual")
		private Integer empId;
	
	应用场景:购物车结账后
		增加商品销量
		减少商品库存
		生成订单数据-->封装到Order对象中-->保存Order对象-->数据库自动生成主键值-->回写到实体类Order对象中
		生成一系列订单详情数据-->List<OrderItem>-->在每一个OrderItem中设置Order对象的主键值作为外键-->批量保存List<OrderItem>

六、常用方法:

1.T selectOne(T var1)
	通用Mapper替我们自动生成的SQL语句
	方法中传入一个实体类,根据实体类对象参数,查询数据库中一条数据
	Employee employeeQueryCondiction = new Employee(null,"bob",5560.11,null);
	Employee employeeQueryResult = employeeService.selectOne(employeeQueryCondiction); //dao调用selectOne
	
	实体类封装查询条件生成WHERE子句的规则:
		·使用非空的值生成WHERE子句
		·在条件表达式中都是使用 "=" 进行比较
	
	要求必须返回一个实体类结果,如果有多个,会抛出异常
	
2.List<T> selectAll()
	查询所有,返回List集合,不需要参数

3.List<T> select(T var1)
	通过实体类对象,封装查询条件,可以查询多个,返回List集合

4.int selectCount(T var1)
	查询个数
	
5.T selectByPrimaryKey(Object var1)
	根据主键查询,需要根据一个主键,使用@Id注解明确标记和数据库中主键字段对应的实体类属性。
	否则:会报错,它会将实体类中所有的字段集合起来,作为联合主键
	
6.boolean existsWithPrimaryKey(Object var1)

7.int insert(T var1)
	插入数据操作
	
	Employee employee= new Employee(null,"cat",6666.66,null);
	employeeService.insert(employee); // dao调用insert
	
	//一般情况下返回null
	//如果empId为自增的主键,并且在实体类的 empId 属性上添加了 @GeneratedValue(strategy=GeneratedType.IDENTITY)
	Integer empId = employee.getEmpId();
	
8.xxxSelective(T var1)
	非主键字段如果为null值,则不会加入到SQL语句中
	例如:int insertSelective(T var1)
		适合表中字段挺多,但是插入数据很少是场景
		可以省略插入数据是为null的字段,使得sql语句比较简洁可以省略插入数据是为null的字段,使得sql语句比较简洁
		
9.int updateByPrimaryKey(T var1)

10.int updateByPrimaryKeySelective(T var1)
	在改数据库中的数据,并不是所有的数据都需要更改,这是需要采用这个方法。
	
11.int delete(T var1);
	在条件表达式中都是使用 "=" 进行比较
	注意:如果var1=null; 会将所有的数据都删除掉,需要先进行判断。

12.int deleteByPrimaryKey(Object var1);

七、QBC查询

query by criteria
criteria:是criterion的复数形式。意思是:规则、标准。在SQL语句中相当于查询条件。
QBC查询是将查询条件通过Java对象进行模块化封装。

例子:
目标: WHERE (emp_salary>? AND emp_age<?) OR (emp_salary<? AND emp_age>?)

	//1.创建Example对象
	Example example = new Example(Employee.class);
	/*
		example可以设置:
		//1.设置查询结果排序信息
		example.orderBy("empSalary").asc().orderBy("empAge").desc();
		//2.设置查询结果“去重”
		example.setDistinct(true);
		//3.设置查询结果select字段
		example.selectProperties("empSalary","empAge");
	*/
	
	//2.通过Example对象创建Criteria对象
	Criteria criteria01 = example.createCriteria();
	Criteria criteria02 = example.createCriteria();
	
	//3.在两个Criteria对象中分别设置查询条件
	criteria01.addGreaterThan("empSalary",3000).andLessThan("empAge",25);
	criteria02.addLessThan("empSalary",5000).andGreaterThan("empAge",30);
	
	//4.使用OR关键字组装两个Criteria对象
	example.or(criteria02);
	
	//5.执行查询
	List<Employee> empList = employeeService.getEmpListByExample(example);
	/*
		在service中使用dao接口调用
		dao.selectByExample(example);
	*/

八、类型处理器:TypeHandler

1.简单类型和复杂类型
	
	基本数据类型:byte,short,int,long,float,double,char,boolean
	引用数据类型:类、接口、数组、枚举....
	
	简单类型:只要一个值的类型
	复杂数据类型:有多个值的类型
	
  通用Mapper默认情况下会忽略复杂类型,对复杂类型不进行类到表的映射。
  
2.自定义类型转换器
	
	一般情况下表中的数据字段会和实体类属性对应,但也有不对应的情况:
		1)一对多、多对多的关系
			这时需要建立关联表
		2)有时候业务需求,需要一些特殊类型的数据
			可以使用通用Mapper的类型转换器
	
			Address对象 <-----> TypeHandler <-----> 字符串
		
	

3.实例1

	1)新建一个类,继承通用Mapper的BaseTypeHandler,重写方法,实现自定义Address类型转换:
	
	public class AddressTypeHandler extends BaseTypeHandler<Address>{
		
		@Override
		public void setNotNullParameter(PreparedStatement ps, int i, Address address, 
			JdbcType jdbcType) throws Exception{
			
			//1.对数据进行验证
			if(address == null){
				return ;
			}
			
			//2.从address对象中取出具体数据
			String province = address.getProvince();
			String city = address.getCity();
			String street = address.getStreet();
			
			//3.拼装成一个字符串
			// 自定义规则:各个值之间使用","分开
			StringBuilder builder = new StringBuilder();
			builder
				.append(province).append(",")
				.append(city).append(",")
				.append(street);
			String parameterValue = builder.toString();
			
			//4.设置参数
			ps.serString(i,parameterValue);
			
		}
		
		@Override
		public Address getNullableResult(ResultSet rs,String columnName)throws SQLException{
			
			//1.根据字段名从rs对象中获取字段值
			String columnValue = rs.getString(columnName);
			
			//2.验证columnName是否有效
			if(columnValue == null || columnValue.length == 0 || !columnValue.contains(",")){
				reruen ;
			}
			
			//3.根据","columnValue进行拆分
			String[] split = columnValue.split(",");
			
			//4.从拆分结果数组中获取Address需要的具体数据
			String province = split[0];
			String city = split[1];
			String street = split[2];
			
			//5.根据具体对象组装一个Address对象
			Address address = new Address(province,city,street);
			
			return address;
		}
		
		@Override
		public Address getNullableResult(ResultSet rs,int columnIndex)throws SQLException{
			//1.根据索引从rs对象中获取字段值
			String columnValue = rs.getString(columnIndex);
			
			//2.验证columnName是否有效
			if(columnValue == null || columnValue.length == 0 || !columnValue.contains(",")){
				reruen ;
			}
			
			//3.根据","columnValue进行拆分
			String[] split = columnValue.split(",");
			
			//4.从拆分结果数组中获取Address需要的具体数据
			String province = split[0];
			String city = split[1];
			String street = split[2];
			
			//5.根据具体对象组装一个Address对象
			Address address = new Address(province,city,street);
			
			return address;
		}
		
		@Override
		public Address getNullableResult(CallableStatement cs, int columnIndex)throws Example{
			//1.根据索引从cs对象中获取字段值
			String columnValue = cs.getString(columnIndex);
			
			//2.验证columnName是否有效
			if(columnValue == null || columnValue.length == 0 || !columnValue.contains(",")){
				reruen ;
			}
			
			//3.根据","columnValue进行拆分
			String[] split = columnValue.split(",");
			
			//4.从拆分结果数组中获取Address需要的具体数据
			String province = split[0];
			String city = split[1];
			String street = split[2];
			
			//5.根据具体对象组装一个Address对象
			Address address = new Address(province,city,street);
			
			return address;
		}
	}
	
	
	2)注册自定义类型转换器
		
		方法一:字段级别:@ColumnType注解
			public class user{
				
				private Integer userId;
				private String userName;
				
				@ColumnType(typeHandler=AddressTypeHandler.class)
				private Address address;
				private SeasonEnum season;
				....
			}
		
		方法二:全局级别:在Mybatis配置文件中配置 typeHandlers
			
			//第一步:在实体类中该字段上加入@Column,作用是让通用Mapper不忽略这个类型
			public class user{
				
				private Integer userId;
				private String userName;
				
				@Column
				private Address address;
				private SeasonEnum season;
				....
			}
			
			//第二步:在mybatis.xml文件中配置
			<typeHandlers>
				<!--handler属性:指定自定义类型转换器全限定名称-->
				<!--javaType属性:指定需要自定义类型转换器转换的实体类的全限定名称-->
				<typeHandler 
					handler="com.company.handlers.AddressTypeHandler" 
					javaType="com.company.domain.Address"/>
			</typeHandlers>




4.实例2 枚举类型
	
	办法一:让通用Mapper把枚举类型作为简单类型处理
	
		增加一个通用Mapper的配置项,在ApplicationContrxt.xml配置通用Mapper的bean中
		<!-- 扫描dao接口 -->
		<bean id="mapperScanner" class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
			<property name="basePackage" value="com.company.dao"/>
			<property name="properties">
				<value>
					enumAsSimpleType=true
				</value>
			</property>
		</bean>
		
	
	办法二:为枚举类型配置对应的类型处理器
	
		枚举对象 <-----> TypeHandler <-----> 字符串
		
		枚举类型转换器:
			
			1)mybatis内置两种处理器:
				org.apache.ibatis.type.EnumTypeHandler<E> //在数据库中存储枚举值本身
				
				org.apache.ibatis.type.EnumOrdinalTypeHandler<E> //在数据库中仅仅存储枚举值索引
				
			   内置枚举类型转换器的注册:
				由于泛型的存在,不能使用@ColumnType注解注册mybatis内置的枚举类型转换器
				
				可以在mybatis.xml文件中配置,但是注意不要加泛型
				<typeHandlers>
					<!--handler属性:指定自定义类型转换器全限定名称-->
					<!--javaType属性:指定需要自定义类型转换器转换的实体类的全限定名称-->
					<typeHandler 
						handler="org.apache.ibatis.type.EnumTypeHandler" 
						javaType="com.company.domain.SeasonEnum"/>
				</typeHandlers>
				
			2)自定义类型转换器
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值