mybatis
- 1、 问题
- 2、使用
- 3、#与$
- 3.1 例子
- 3.2什么情况下必须使用${}
- 4、别名机制
- 5 、Mapper配置
- 6、配置模板文件
- 7、使用自动生成的主键
1、 问题
在上一篇mybtis的web项目中,我们最后有一个问题没有解决,就是dao的实现类,其代码很类似,只是具体执行的sql语句不同,那么我们是否可以只编写dao的接口,而不用编写其具体实现类呢?
当然可以,mybaits已经二次封装了javassist来帮助我们自动生成实现类。
但是如果我们要使用这一机制,就要注意:
我们xxxmapper.xml 文件的namespace必须是 dao的接口全限定符,并且sql的id必须与接口的方法名一致
。这有助于我们使用javassist这一辅助工具生成代理类是其可以帮助我们自动去实现接口的方法,并且调用我们自己编写的sql语句。
2、使用
1、首先 导入mybatis mysql logback junit依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.cky</groupId><artifactId>proxy</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target></properties><dependencies><!-- mybatis--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.10</version></dependency><!-- mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.30</version></dependency><!-- logback--><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.11</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency></dependencies></project>
2、写pojo 类
package com.cky.pojo;public class Car {private Integer id;private String carNum;private String brand;private Double guidePrice;private String produceTime;private String carType;public Car(Integer id, String carNum, String brand, Double guidePrice, String produceTime, String carType) {this.id = id;this.carNum = carNum;this.brand = brand;this.guidePrice = guidePrice;this.produceTime = produceTime;this.carType = carType;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getCarNum() {return carNum;}public void setCarNum(String carNum) {this.carNum = carNum;}public String getBrand() {return brand;}public void setBrand(String brand) {this.brand = brand;}public Double getGuidePrice() {return guidePrice;}public void setGuidePrice(Double guidePrice) {this.guidePrice = guidePrice;}public String getProduceTime() {return produceTime;}public void setProduceTime(String produceTime) {this.produceTime = produceTime;}public String getCarType() {return carType;}public void setCarType(String carType) {this.carType = carType;}@Overridepublic String toString() {return "Car{" +"id=" + id +", carNum='" + carNum + '\'' +", brand='" + brand + '\'' +", guidePrice=" + guidePrice +", produceTime='" + produceTime + '\'' +", carType='" + carType + '\'' +'}';}
}
3、写mapper接口
package com.cky.Mapper;import com.cky.pojo.Car;import java.util.List;public interface CarMapper {List<Car> selectAllCar();int deletebyId(int id);
}
4、写工具类 获得session
package com.cky.utils;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 java.io.IOException;public class MybatisUtils {private static SqlSessionFactory sqlSessionFactory;/*** 类加载时初始化sqlSessionFactory对象*/static {SqlSessionFactoryBuilder sqlSessionFactoryBuilder=new SqlSessionFactoryBuilder();try {sqlSessionFactory=sqlSessionFactoryBuilder.build(Resources.getResourceAsReader("mybatis-config.xml"));} catch (IOException e) {e.printStackTrace();}}/*** 每调用一次openSession()可获取一个新的会话,该会话支持自动提交。** @return 新的会话对象*/public static SqlSession openSession(){return sqlSessionFactory.openSession(true);}
}
5、写mapper.xml文件
注意namespace 和 id
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace先随意写一个-->
<mapper namespace="com.cky.Mapper.CarMapper"><select id="selectAllCar" resultType="com.cky.pojo.Car">select id,car_num,brand,guide_price,produce_time,car_type from t_car ;</select><delete id="deletebyId">delete from t_car where id=#{id};</delete>
</mapper>
6、写mybaits.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><properties resource="jdbc.properties"></properties>
<!--一个数据库对应一个一个环境,一个数据库对应一个sqlSessionFactory对象-->
<!-- 即一个环境 对应一个sqlSessionFactory对象-->
<!-- 默认 使用的是defalut的数据库--><environments default="mybatisDB"><environment id="mybatisDB"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.name}"/><property name="password" value="${jdbc.pwd}"/></dataSource></environment></environments><mappers><!--sql映射文件创建好之后,需要将该文件路径配置到这里--><mapper resource="CarMapping.xml"/></mappers>
</configuration>
7 、测试
使用以下代码的前提是:CarMapper.xml文件中的namespace必须和dao接口的全限定名称一致,id必须和dao接口中方法名一致。
package com.cky;import com.cky.Mapper.CarMapper;
import com.cky.pojo.Car;
import com.cky.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;import java.util.List;public class test {@Testpublic void tesr(){SqlSession sqlSession = MybatisUtils.openSession();//getMapper() 参数传入我们要代理的接口类 之后底层 会调用javassist 自动帮助我们生成 实现类 并将实现类返回 我们可以直接调用接口类的方法CarMapper mapper = sqlSession.getMapper(CarMapper.class);List<Car> cars = mapper.selectAllCar();cars.forEach(car -> System.out.println(car));int i = mapper.deletebyId(6);System.out.println(i);sqlSession.commit();sqlSession.close();}
}
3、#与$
3.1 例子
比如 我们需要根据汽车类型来查询汽车
List<Car> selectbyCarType(String type);
<select id="selectbyCarType" resultType="com.cky.pojo.Car">select * from t_car where car_type=${cartype}</select>
如果使用${}
则会报错
因为${} 是先进行sql语句的拼接,然后再编译,出现语法错误是正常的,因为 燃油车 是一个字符串,在sql语句中应该添加单引号
如果使用#{}
则正确.
通过执行可以清楚的看到,sql语句中是带有 ? 的,这个 ? 就是大家在JDBC中所学的占位符,专门用来接收值的。把“电车”以String类型的值,传递给 ? 这就是 #{},它会先进行sql语句的预编译,然后再给占位符传值
3.2什么情况下必须使用${}
当需要进行sql语句关键字拼接的时候。必须使用${}
需求:通过向sql语句中注入asc或desc关键字,来完成数据的升序或降序排列。
<select id="selectAll" resultType="com.cky.pojo.Car">selectid,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carTypefromt_carorder by carNum #{key}</select>
@Testpublic void testCartype1(){SqlSession sqlSession = MybatisUtils.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);List<Car> cars = mapper.selectAll("desc");cars.forEach(desc-> System.out.println(desc));}
使用#{}
错误,因为会先预编译,在赋值,这时候 会将其作为一个字符串常量传进去,但是是错误的 decs 是一个关键字,加上’'会变成字符串常量,sql语句会出错。
使用${}
此时是拼接,正确。
其他情况可能也需要 使用${} ,不在叙述,比如表名拼接时,此时是作为关键字而不是字符串常量赋值,或者模糊查询时 比如%奔驰% 如果要传入 奔驰这个关键字 就不能'%#{type}%' ,因为这时候 #{} 是在‘’引号里,不会被认为是占位符,使用${} 可以直接拼接。
我们如果想使用${} 可以 ”%“#{}”% “ 使用双引号的方式。也可以使用concat函数拼接, brand like concat('%',#{brand},'%')
4、别名机制
比如我们每次都returnType 上 都需要写全限定类名,很麻烦,我们可以采用别名机制。
在mybatis.xml文件中 配置
有三种方式
①对某个类 自己起别名
②对某个类采用默认别名机制
③对包下的类都采用默认别名机制
<typeAliases><!-- 自己起别名 --><typeAlias type="com.cky.pojo.Car" alias="car"></typeAlias><!-- 采用默认别名机制 默认是类名 --><typeAlias type="com.cky.pojo.Car"></typeAlias><!-- 对包下所有的类 都采用默认别名机制 --><package name="com.cky.pojo"/></typeAliases>
5 、Mapper配置
SQL映射文件的配置方式包括四种:
● resource:从类路径中加载
● url:从指定的全限定资源路径中加载
● class:使用映射器接口实现类的完全限定类名
● package:将包内的映射器接口实现全部注册为映射器
前两种方式
<mappers ><mapper resource="CarMapper.xml"/><mapper url="file:///d:CarMapper.xml"/></mappers>
第三种方式
<mappers><mapper class="com.cky.Mapper.CarMapper"/></mappers>
有个前提:
如果使用这种方式必须满足以下条件:
● SQL映射文件和mapper接口放在同一个目录下。
● SQL映射文件的名字也必须和mapper接口名一致。
虽然在不同的地方,其实都是在根路径下,java和resources打包后最后都在同一个目录下。
第四种方式
将包内的映射器接口实现全部注册为映射器 ,这种方式条件和第三种一样。
<mappers><package name="com.cky.Mapper"/></mappers>
注意
在resources下只能创建目录 不能创建包
不能使用com.cky.Mapper 的方式 这样其实还是一个一级目录。
应该使用com/cky/Mapper 这是创建多级目录。
6、配置模板文件
比如我们的mybatis配置文件和 xxxMapper.xml,我们可以配置模板文件,方便创建。
举例:
7、使用自动生成的主键
不需要我们自己设置主键 而是mybaits帮我们自动生成 并且返回给我们。
<insert id="insertCargeneratedkey" useGeneratedKeys="true" keyProperty="id">insert into t_car values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})</insert>
@Testpublic void test(){SqlSession sqlSession = MybatisUtils.openSession();CarMapper mapper = sqlSession.getMapper(CarMapper.class);Car car=new Car(null,"1000","1",100.0,"2024-04-09","dianche");int i = mapper.insertCargeneratedkey(car);System.out.println(i);System.out.println(car);sqlSession.commit();sqlSession.close();}
虽然我们插入的car id为null,但是当我们再次获取输出car时我们可以看到其id是有值的,
useGeneratedKeys=“true” 表示我们需要生成的主键值,keyProperty=“id” 代表将生成的主键值赋给id这个属性。此时当我们插入时,就会将自动生成的主键值赋给id,如果为false,则我们输出时car的id为null,虽然数据库中car的id是有值的,但是由于没有回显,输出就为null。