mybatis在GitHup上的源码官网:https://github.com/mybatis/mybatis-3
maven远程库依赖官网:https://mvnrepository.com/
mybatis官方学习文档:https://mybatis.org/mybatis-3/zh/index.html
MyBatis入门程序
数据库表案例(汽车表)
mybatis-config.xml 配合 jdbc.properties 配置文件使用
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--引用jdbc.properties数据库连接 配置文件-->
<properties resource="jdbc.properties"/>
<settings>
<!--
是否开启驼峰命名自动映射,前提是有保证pojo类和数据库对应
即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。
默认是false不开启的
-->
<setting name="mapUnderscoreToCamelCase" value="false"/>
<!--配置mybatis自带日志-->
<!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->
</settings>
<!--
typeAliases标签:起别名
两种形式:
1、给一个类起别名:(不区分大小写)
<typeAlias type="com.mybatis.pojo.Car" alias="Car"></typeAlias>
type:给谁起别名,alias:别名叫什么(可省略,省略之后别名就是类名)
2、给整个包中的所有类起别名:(不区分大小写)
<package name="com.mybatis.pojo"/>
(建议使用)这个会自动将包中所有的类起别名,别名就是类名
-->
<typeAliases>
<package name="com.mybatis.pojo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!--
指定XxxMapper.xml文件的路径
三种形式:
第一种:<mapper resource="CarMapper.xml"/>
resource属性自动会从类的根路径下开始查找资源
第二种:<mapper url=""></mapper>
不使用这种绝对路径的形式:可移植性太差
第三种(实际开发使用):<package name="com.mybatis.pojo"/>
直接指定mapper.xml文件所在包(前提是要在resources目录下创建mapper同级目录)
-->
<mappers>
<package name="com.mybatis.mapper"/>
</mappers>
</configuration>
<!-- #{}和${}的区别:
#{}:底层使用PreparedStatement。特点:先进行sql语句的编译,然后给sql语句的占位符问号?传值
${}:底层使用Statement。特点:先进行sql语句的拼接,然后再对sql语句进行编译。存在sql注入的风险
优先使用#{},这是原则。避免sql注入的风险
(1、)如果需要sql语句的关键字放到sql语句中,只能使用${},因为#{}是以值的形式放到sql语句当中的。
(2、)向sql语句当中拼接表名,就需要使用${}
(3、)批量删除:一次删除多条记录的时候,使用in(${})
(4、)模糊查询的时候 '%${}%'
-->
jdbc.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/powernode
username=root
password=root
CarMapper
package com.mybatis.mapper;
import com.mybatis.pojo.Car;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface CarMapper {
/**
* @description: 根据id查询
* @param id:
* @return java.util.List<com.mybatis.pojo.Car>
* @author: hz
* @date: 2022/12/11
*/
List<Car> selectById(Long id);
/**
* @description: 多参数查询,根据品牌和汽车类型查询
* @param brand: 品牌
* @param carType: 类型
* @return java.util.List<com.mybatis.pojo.Car>
* @author: hz
* @date: 2022/12/11
*/
List<Car> selectByBrandAndCarType(@Param("brand") String brand, @Param("carType") String carType);
/**
* 根据汽车品牌模糊查询,返回结果存放在,存放Map集合的List集合
* @param brand:品牌
*/
List<Map<String ,Object>> selectCarByBrand(@Param("brand") String brand);
/**
* 查询所有的Car,返回一个大Map集合
* Map集合的key 是每条记录的主键值
* Map集合的Value是每条记录。
* @param :
*/
@MapKey("id")//将查询结构的id值作为整个大Map集合的Key。
Map<Long ,Map<String ,Object>> selectCarAllReturnMap();
/**
* 获取Car的总记录条数
*/
Long selectCountTotal();
/**
* 多条件查询 使用where标签
* @param brand: 品牌
* @param guidePrice: 指导价
* @param carType: 汽车类型
*/
List<Car> selectByMultiCondition(@Param("brand") String brand,
@Param("guidePrice") Double guidePrice,
@Param("carType") String carType);
/**
* 多条件查询:使用trim标签
*/
List<Car> selectByMultiCondition2(@Param("brand") String brand,
@Param("guidePrice") Double guidePrice,
@Param("carType") String carType);
/**
* 使用choose when otherwise标签 单条件查询
* @param brand:
* @param guidePrice:
* @param carType:
*/
List<Car> selectByChoose(@Param("brand") String brand,
@Param("guidePrice") Double guidePrice,
@Param("carType") String carType);
/**
* 更新car
* @param car:
*/
int updateById(Car car);
/**
* 更新car : 使用set标签更新
* @param car:
*/
int updateById2(Car car);
/**
* 批量删除 foreach标签
* @param ids:
*/
int deleteByIds(@Param("ids") Long[] ids);
/**
* 批量删除 foreach标签
* @param cars:
*/
int insertBach(@Param("cars") List<Car> cars);
/**
* 查询所有
*/
List<Car> getAllCar();
}
CarMapper.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">
<!--namespace写mapper接口的全限定接口名(XxxMapper内含很多增删改查方法的接口)-->
<mapper namespace="com.mybatis.mapper.CarMapper">
<!--
+____+_________+__________+_____________+______________+__________+
| id | car_num | brand | guide_price | produce_time | car_type |
+____+_________+__________+_____________+______________+__________+
| 1 | 299 | 保时捷 | 60.00 | 2021-12-12 | 新能源 |
| 2 | 888 | 奔驰 | 33.00 | 2011-1-11 | 燃油车 |
+____+_________+__________+_____________+______________+__________+
-->
<!--
专门定义一个结果集映射,在这个结果集映射当中 指定数据库表的字段 和 java类的属性名的对应关系
1.type属性:用来指定pojo类的类名
2.id属性:指定resultMap的唯一标识,这个id要在select标签中使用。
-->
<resultMap id="carResultMap" type="com.mybatis.pojo.Car">
<!--如果表中有主键,建议这里配置一个id标签。注意这个不是必须的,但官方解释:这样可以提高执行效率-->
<id property="id" column="id"/>
<!--property:后面写pojo类中的属性-->
<!--column:后面写数据库表的字段名-->
<result property="carNum" column="car_num"/>
<!--如果列column和property是一样的,这种可以省略,但我基本全写了-->
<result property="brand" column="brand"/>
<result property="guidePrice" column="guide_price"/>
<result property="produceTime" column="produce_time"/>
<!--javaType="string(自带别名)" jdbcType="VARCHAR"写了提高效率,不写mybatis也会自动做类型推断,基本省略不写-->
<result property="carType" column="car_type" javaType="string" jdbcType="VARCHAR"/>
<!--
<association property="多表查询中关联的另一张表" javaType="">
<id property="" column=""></id>
<result property="" column=""></result>
<result property="" column=""></result>
</association>
-->
</resultMap>
<!--方法:List<Car> selectById(Long id);
id:这条sql语句的唯一标识(一般就是这条sql语句在mapper接口中的方法名)
resultType:查询结果集的返回值类型(一般返回的是实体类,(设置了别名,我基本不使用别名(会有mybatis插件冲突)))
parameterType:告诉mybatis我这个方法的参数类型(自带别名)一般省略不写。
resultMap:结果集映射的id
-->
<select id="selectById" resultMap="carResultMap" parameterType="long">
select * from t_car where id=#{id}
</select>
<!--
使用多参数查询时:
mapper接口中方法传的的参数要使用@Param注解,来指定Map集合中的key
即方法:List<Car> select..(@Param("brand") String brand, @Param("carType") String carType);
-->
<select id="selectByBrandAndCarType" resultType="com.mybatis.pojo.Car">
select * from t_car where brand=#{brand} and car_type=#{carType}
</select>
<!--方法:List<Map<String ,Object>> selectCarByBrand(@Param("brand") String brand);-->
<!--这里mapper接口方法中使用Map集合接收的结果集。resultType="java.util.Map" 有别名:map-->
<select id="selectCarByBrand" resultType="map">
select * from t_car where brand like "%"#{brand}"%"
</select>
<!--
查询所有的Car,返回一个大Map集合
@MapKey("id")//将查询结构的id值作为整个大Map集合的Key。
Map<Long ,Map<String ,Object>> selectCarAllReturnMap();
-->
<select id="selectCarAllReturnMap" resultType="map">
select * from t_car
</select>
<!--查询总记录条数:Long selectCountTotal();-->
<select id="selectCountTotal" resultType="long">
<!--count(具体字段)时,会自动去除空值-->
select count(*) from t_car
</select>
<!--动态sql动态sql动态sql动态sql动态sql动态sql动态sql动态sql动态sql动态sql动态sql动态sql动态sql动态sql动态sql-->
<!--where,if语句:
* 多条件查询
* @param brand: 品牌
* @param guidPrice: 指导价
* @param carType: 汽车类型
List<Car> selectByMultiCondition(@Param("brand") String brand,
@Param("guidPrice") Double guidePrice,
@Param("carType") String carType);
-->
<select id="selectByMultiCondition" resultType="com.mybatis.pojo.Car">
select * from t_car
<!--where标签,当里面的所有条件为空时,where标签保证不会生产where子句。-->
<!--自动会去除某些条件 前面 的and或or,常和if标签联合使用。注意:wher标签是没有办法去除后面的and或or的-->
<where>
<!--if标签中的test属性是必须的(表达式,也就是条件),值为 false | true 如果为true就会拼接执行,反之则不会拼接-->
<!--当使用了@Param注解,test中要出现@Param指定的参数,且只能使用这些参数-->
<!--没有使用@Param注解,test中要出现的是:param1,param2...arg0,arg1...-->
<!--当使用了pojo,那么test中出现的是pojo类的属性名-->
<if test="brand != null and brand !=''">
and brand like "%"#{brand}"%"
</if>
<if test="guidePrice != null and guidePrice !=''">
and guide_price > #{guidePrice}
</if>
<if test="carType != null and carType !=''">
and car_type = #{carType}
</if>
</where>
</select>
<select id="selectByMultiCondition2" resultType="com.mybatis.pojo.Car">
select * from t_car
<!--trim标签:常和if标签联合使用
prefix:加前缀
suffix:加后缀
prefixOverrides:去除前缀
suffixOverrides:去除后缀
-->
<!--prefix="where":在trim标签中所有内容的前面添加where-->
<!--suffixOverrides="and | or":把trim标签中所有内容的后缀and或or去掉-->
<trim prefix="where" suffixOverrides="and | or" >
<if test="brand != null and brand !=''">
brand like "%"#{brand}"%" and
</if>
<if test="guidePrice != null and guidePrice !=''">
guide_price > #{guidePrice} and
</if>
<if test="carType != null and carType !=''">
car_type = #{carType}
</if>
</trim>
</select>
<!--根据choose when otherwise标签查询-->
<select id="selectByChoose" resultType="com.mybatis.pojo.Car">
select * from t_car
<where>
<!--相当于java里的if else if else-->
<!--只会执行一句sql语句(为真的),都为真就执行第一句(不往后执行了),都为假就只执行最后一句(传null值)-->
<!--至少执行一句,但也只会执行一句!-->
<choose>
<when test="brand != null and brand != ''">
brand like "%"#{brand}"%"
</when>
<when test="guidePrice != null and guidePrice != ''">
guide_price > #{guidePrice}
</when>
<otherwise>car_type = carType</otherwise>
</choose>
</where>
</select>
<!--普通的更新汽车信息:int updateById(Car car);-->
<update id="updateById">
update t_car set
car_num = #{carNum},
brand = #{brand},
guide_price = #{guidePrice},
produce_time = #{produceTime},
car_type = #{carType}
where
id = #{id}
</update>
<!--使用set标签语句更新,完成只更新传过来的数据不为空且不为空字符串的数据-->
<!--注意:set标签要和if标签联合使用,且会自动去除后面多余的逗号 , -->
<update id="updateById2">
update t_car
<!--set标签-->
<set>
<if test="carNum != null and carNum != ''">car_num = #{carNum},</if><!--sql后面的逗号不能丢-->
<if test="brand != null and brand != ''">brand = #{brand},</if>
<if test="guidePrice != null and guidePrice != ''">guide_price = #{guidePrice},</if>
<if test="produceTime != null and produceTime != ''">produce_time = #{produceTime},</if>
<if test="carType != null and carType != ''">car_type = #{carType}</if>
</set>
where id = #{id}
</update>
<!--批量删除 foreach标签-->
<delete id="deleteByIds">
delete from t_car where id in
<!--
collection:指定数组或者集合
item:代表数组或者集合中的元素
separator:循环之间的分隔符
open:(省略了in()的括号),foreach循环自动拼接sql语句,这条循环最前面以什么开始
close:foreach循环自动拼接sql语句,这条循环最后面以什么结束
-->
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
<!--批量插入 foreach标签-->
<insert id="insertBach">
insert into t_car values
<!--这里不用open和close的,因为每条value都是有括号()的-->
<foreach collection="cars" item="car" separator=",">
(null,<!--id自动生成的-->
#{car.carNum},<!--集合中的元素car点上属性-->
#{car.brand},
#{car.guidePrice},
#{car.produceTime},
#{car.carType}
)
</foreach>
</insert>
<!--sql片段标签,提高复用性-->
<sql id="carColumnNameSql">
id,
car_num as carNum,
brand,
guide_price as guidePrice,
produce_time as produceTime,
car_type as carType
</sql>
<select id="getAllCar" resultType="com.mybatis.pojo.Car">
select
<!--include标签,引用sql片段-->
<include refid="carColumnNameSql"/>
from t_car
</select>
</mapper>
<!---->
Car
package com.mybatis.pojo;
public class Car {
//数据库表中的字段应该和pojo类的属性一一对应
//使用包装类,这样可以防止null的问题
private Long id;
private String carNum;
private String brand;
private Double guidePrice;
private String produceTime;
private String carType;
//无参、含参、toString()、get()、set()
}
SqlSessionUtil
package com.mybatis.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;
public class SqlSessionUtil {
private SqlSessionUtil(){}
private static SqlSessionFactory sqlSessionFactory;
static {
try {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static SqlSession openSession(){
return sqlSessionFactory.openSession();
}
}
log4j.xml
<?xml version="1.0" encoding="GB2312" ?>
<!DOCTYPE log4j:configuration SYSTEM "http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd">
<log4j:configuration debug="true">
<appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
<param name="Encoding" value="UTF-8" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" />
</layout> </appender>
<logger name="java.sql">
<level value="debug" />
</logger> <logger name="org.apache.ibatis">
<level value="info" />
</logger> <root><level value="debug" />
<appender-ref ref="STDOUT" /> </root>
</log4j:configuration>
CarMapperTest
package mybatis.mapper;
import com.mybatis.mapper.CarMapper;
import com.mybatis.pojo.Car;
import com.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author Administrator
* @ClassName CarMapperTest
* @description:
* @date 2022-12-08
* @version: 1.0
*/
public class CarMapperTest {
/**
* 根据id查询
* @param
* @return
*/
@Test
public void selectById(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
List<Car> cars = mapper.selectById(1L);
cars.forEach(car -> System.out.println(car));
sqlSession.close();
}
/**
* 多参数查询
* 根据品牌和汽车类型查询
* @param
* @return
*/
@Test
public void selectByBrandAndCarType(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
List<Car> cars = mapper.selectByBrandAndCarType("保时捷", "新能源");
cars.forEach(car -> System.out.println(car));
sqlSession.close();
}
/**
* 根据汽车品牌模糊查询,返回结果存放在,存放Map集合的List集合
*/
@Test
public void selectCarByBrand(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
List<Map<String, Object>> byBrands = mapper.selectCarByBrand("奔驰");
byBrands.forEach(brand -> System.out.println(brand));
sqlSession.close();
}
/**
* 查询所有的Car,返回一个大Map集合
* Map集合的key 是每条记录的主键值
* Map集合的Value是每条记录。
* @param :
*/
@Test
public void selectCarAllReturnMap(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Map<Long, Map<String, Object>> maps = mapper.selectCarAllReturnMap();
maps.forEach((key, value) -> System.out.println(key+":"+value));
sqlSession.close();
}
/**
* 获取Car的总记录条数
*/
@Test
public void selectCountTotal(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Long countTotal = mapper.selectCountTotal();
System.out.println(countTotal);
sqlSession.close();
}
/**
* 多条件查询
*/
@Test
public void selectByMultiCondition(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
List<Car> cars = mapper.selectByMultiCondition2("奔驰",2.0,"燃油车");
cars.forEach(car -> System.out.println(car));
sqlSession.close();
}
/**
* 使用choose when otherwise标签查询
*/
@Test
public void selectByChoose(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
List<Car> cars = mapper.selectByChoose("丰田霸道", null, "燃油车");
cars.forEach(car -> System.out.println(car));
sqlSession.close();
}
/**
* 更新car信息
* @param :
*/
@Test
public void updateById(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Car car = new Car(31L, null, "宾利", null, null, "燃油车");
int i = mapper.updateById2(car);
System.out.println(i);
sqlSession.commit();
sqlSession.close();
}
/**
* 批量删除 foreach标签
*/
@Test
public void deleteByIds(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Long[] ids = {31L,45L};
int count = mapper.deleteByIds(ids);
System.out.println(count);
sqlSession.commit();
sqlSession.close();
}
/**
* 批量插入 foreach标签
*/
@Test
public void insertBach(){
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
Car car1 = new Car(null,"1200","帕萨特",70.0,"2000-11-11","燃油车");
Car car2 = new Car(null,"1300","福特",80.0,"2000-11-11","燃油车");
Car car3 = new Car(null,"1400","凯迪拉克",90.0,"2000-11-11","燃油车");
Car car4 = new Car(null,"1500","兰博基尼",100.0,"2000-11-11","燃油车");
ArrayList<Car> cars = new ArrayList<>();
cars.add(car1);
cars.add(car2);
cars.add(car3);
cars.add(car4);
int insertBach = mapper.insertBach(cars);
System.out.println(insertBach);
sqlSession.commit();
sqlSession.close();
}
/**
* 查询所有
*/
@Test
public void getAllCar() {
SqlSession sqlSession = SqlSessionUtil.openSession();
CarMapper mapper = sqlSession.getMapper(CarMapper.class);
List<Car> cars = mapper.getAllCar();
cars.forEach(car -> System.out.println(car));
sqlSession.close();
}
}
pom.xml
<?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.powernode</groupId>
<artifactId>mybatis_001_introduction</artifactId>
<version>1.0-SNAPSHOT</version>
<!--打包方式jar,因为不需要部署到tomcat服务器中,所有不需要war-->
<packaging>jar</packaging>
<dependencies>
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
<!--mysql驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
<!--log4j日志依赖-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--junit测试依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
</project>