目录
学习资料:
MyBatis
- MyBatis是一款持久层框架
- MyBatis是半自动的ORM框架,开发时,需要手动编写SQL语句
- 相比JDBC,MyBatis提供了输入映射和输出映射,便于进行SQL参数设置,以及结果集封装。并且还提供了关联查询和动态SQL等功能,极大地提高了开发的效率。
MyBatis实现的设想:
- 使用数据库连接池管理数据库连接
- 将sql语句及占位符号和参数全部配置在xml中
- 将查询的结果集自动映射成java对象
MyBatis基于配置文件的开发步骤:
- 编写全局配置文件configuration
- 编写mapper映射文件,mapper.xml,书写SQL,并定义好SQL的输入、输出参数
- 加载全局配置文件,生成SqlSessionFactory
- 创建SqlSession,调用mapper映射文件中的SQL语句来执行CRUD操作
优点:
- 相较于基于注解的开发,用配置文件更方便后续代码的维护
mybatis-config.xml(配置文件)
- 通过配置文件mybatis-config.xml,MyBatis可以获取到数据库连接信息,配置连接池和事务管理器,并且知道要扫描哪些Mapper.xml文件。在使用MyBatis时,可以通过加载这个配置文件来初始化MyBatis框架,并且获取到对应的数据库操作对象,进行数据库操作。
<configuration> <!--全局配置文件的配置顺序如下 properties //引入放置了数据源信息的properties文件 settings //用来开启或关闭mybatis的一些特性 typeAliases //配置SQL语句的输入、输出参数细节要求等 typeHandlers //用来处理java类型和jdbc类型之间的转换 objectFactory //用于创建对象实例,用得少 plugins //用来配置mybatis的插件 environments //用来配置数据源 environment transactionManager //事务管理器 dataSource //数据源 mappers //映射器 --> </configuration>
<!-- 配置MyBatis核心配置文件 --> <configuration> <!-- 配置数据库连接信息 --> <properties> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mydb"/> <property name="username" value="root"/> <property name="password" value="password"/> </properties> <!-- 配置数据库连接池 --> <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> <!-- 配置Mapper映射文件 --> <mappers> <mapper resource="com/example/mapper/UserMapper.xml"/> </mappers> </configuration>
Mapper.xml(映射文件)
- Mapper.xml文件的作用是将Java对象与数据库表之间进行映射,通过定义SQL语句与实体类之间的对应关系,可以方便地执行数据库操作。在MyBatis框架中,可以通过读取Mapper.xml文件来获取SQL语句,并使用对应的映射关系将查询结果封装成Java对象返回给调用方。这样,我们可以通过简单的配置和调用,实现了数据库操作的解耦和灵活性。
Mapper.xml文件包含以下几个重要的部分:
namespace:命名空间,用于指定Mapper接口的全限定名。
select、insert、update、delete等标签:用于定义 SQL 语句和对应的映射关系。
parameterType:用于指定SQL语句中传入的参数的类型。
resultMap:用于指定查询结果的映射关系,定义了数据库字段与实体类属性之间的对应关系。
SQL语句:可以在Mapper.xml文件中定义多个SQL语句,使用SQL标签包裹SQL语句。可以使用动态SQL语句来动态拼接SQL。
resultType:用于指定查询结果的类型,通常是实体类的类型。
Mapper代理开发
- Mapper代理开发是一种常用的使用MyBatis的方式,它可以通过编写Java接口来定义SQL操作,并通过MyBatis框架自动生成对应的SQL语句和执行逻辑。
- 在使用Mapper代理开发时,只需在MyBatis的配置文件中配置Mapper接口的包路径,MyBatis会自动扫描并生成对应的代理对象。然后,可以通过获取代理对象来使用定义在Mapper接口中的SQL操作方法,而不需要编写具体的SQL语句。
- 实现逻辑:
- 1、定义与SQL映射文件同名的Mapper接口,并且将Mapper接口和SQL映射文件放置在同一目录下。接口和配置文件分开放,但包目录结构是一样的
- 2、设置SQL映射文件中的namespace属性为Mapper接口全限定名
- 3、在Mapper接口中定义方法,方法名就是SQL映射文件中的sql语句中的id,并保持参数类型和返回值类型一致
- 4、调用
//通过SqlSession的getMapper方法获取Mapper接口的代理对象 UserMapper userMapper=sqlSession.getMapper(UserMapper.class); //执行方法,即执行sql语句 List<User> users=userMapper.selectAll();
Mybatis事务
- 在MyBatis中,我们可以使用事务来保证数据库操作的一致性和完整性。MyBatis提供了两种方式来管理事务:基于代码方式和基于注解方式。
- 1、openSession():默认开启事务,需要使用sqlSession.commit();手动提交事务
- 2、openSession(true):自动提交事务
1、基于代码方式
在基于代码方式中,我们需要手动管理事务的开始、提交和回滚。示例代码如下:
public void addUserWithTransaction(User user) {
SqlSession sqlSession = null;
try {
sqlSession = sqlSessionFactory.openSession();
UserDao userDao = sqlSession.getMapper(UserDao.class);
// 开启事务
sqlSession.beginTransaction();
// 执行数据库操作
userDao.addUser(user);
// 提交事务
sqlSession.commit();
} catch (Exception e) {
// 回滚事务
sqlSession.rollback();
e.printStackTrace();
} finally {
// 关闭SqlSession
if (sqlSession != null) {
sqlSession.close();
}
}
}
2、基于注解方式
- 在基于注解方式中,我们可以使用
@Transactional
注解来标识需要进行事务管理的方法。逻辑:
当调用
addUserWithTransaction
方法时,会自动开启事务在Spring配置文件中配置了
<tx:annotation-driven>
来启用注解驱动的事务管理。标注为
@Transactional
的方法被Spring扫描到。通过
@Service
或@Repository
等注解来标识为Spring的Bean。方法执行结束后自动提交或回滚。如果方法执行过程中发生异常,事务会自动回滚
- 示例代码如下:
@Service
public class UserService {
@Autowired
private UserDao userDao;
@Transactional
public void addUserWithTransaction(User user) {
userDao.addUser(user);
}
}
需要确保在Spring配置文件中启用了事务管理器,例如:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
注解开发
- 注解用于完成简单功能(不用写xml文件了)
- 配置文件用于完成复杂功能
- 常用注解:
- 查询:@Select
- 添加:@Insert
- 修改:@Update
- 删除: @Delete
// 导入必要的包 import com.example.entity.User; import org.apache.ibatis.annotations.*; import java.util.List; // 定义Mapper接口 public interface UserMapper { // 插入用户 @Insert("INSERT INTO user (id, name, age) VALUES (#{id}, #{name}, #{age})") void insertUser(User user); // 根据ID查询用户 @Select("SELECT * FROM user WHERE id = #{id}") User getUserById(Integer id); // 更新用户信息 @Update("UPDATE user SET name = #{name}, age = #{age} WHERE id = #{id}") void updateUser(User user); // 根据ID删除用户 @Delete("DELETE FROM user WHERE id = #{id}") void deleteUserById(Integer id); }
配置文件完成增删改查的三步
- 编写接口方法
- 编写SQL
- 执行方法
一、条件查询
1、静态条件查询
静态条件查询是指查询条件固定,在编写SQL语句时就确定了。这种查询适合于查询条件固定不变的情况。
参数接收时,参数的设置:
- 散装参数:如果方法中有多个参数,需要使用@Param("SQL参数占位符名称")
- 对象参数:对象的属性名称要和参数占位符名称一致
- map集合:SQL中的参数名要和map集合的键的名称一致
MyMapper接口
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface MyMapper {
/**
* 根据条件查询数据
* @param name 查询条件:名称
* @param age 查询条件:年龄
* @return 符合条件的数据列表
*/
List<MyEntity> findByCondition(@Param("name") String name, @Param("age") int age);
}
MyMapper.xml
<!-- 在MyMapper.xml中配置SQL语句 -->
<select id="findByCondition" resultType="com.example.MyEntity">
SELECT * FROM my_table
WHERE name = #{name} AND age = #{age}
</select>
2、动态条件查询
- 动态条件查询是指查询条件根据不同情况动态生成的查询,可以根据不同的条件来构建不同的查询语句。
- 标签:
- if:用于判断参数是否有值
- test:逻辑表达式,进行条件判断
- 存在的问题:由于条件数目变化,where可能会和and连接,构成语句错误
- 解决法一:使用恒等式
- 解决法二:使用<where>标签替换where关键字
MyMapper接口
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface MyMapper {
/**
* 动态条件查询数据
* @param condition 查询条件
* @return 符合条件的数据列表
*/
List<MyEntity> findByDynamicCondition(@Param("condition") MyEntity condition);
}
MyMapper.xml
<!-- 在MyMapper.xml中配置动态SQL语句 -->
<select id="findByDynamicCondition" resultType="com.example.MyEntity">
SELECT * FROM my_table
<where>
<if test="condition.name != null">
AND name = #{condition.name}
</if>
<if test="condition.age != null">
AND age = #{condition.age}
</if>
<!-- 可以根据需要添加其他条件 -->
</where>
</select>
二、添加功能
代码示例:
- Mapper接口
void add(Brand brand);
- Mapper.xml
<insert id="add"> insert into tb_brand(brand_name,company_name,ordered,description,status) values(#{brandName},#{companyName},#{ordered},#{description},#{status}); </insert>
- 3、调用方法,测试
- 添加两个属性,使得主键自增
三、修改功能
1、普通修改
Mapper接口
public interface UserMapper {
void updateUser(User user);
}
Mapper.xml
<update id="updateUser" parameterType="com.example.model.User">
UPDATE users SET name = #{name} WHERE id = #{id}
</update>
2、动态修改
在下列示例中,我们创建了一个User对象,并只设置了需要修改的字段值,其他字段值设置为null。在Mapper.xml文件中,我们使用了MyBatis的动态SQL语法,使用
<if>
标签根据User对象的属性值来判断是否包含相应的字段,如果字段值不为null,则将对应的字段和值加入到SQL语句中的<set>
标签中。这样,在执行修改操作时,将只修改非null字段对应的数据,其他字段保持不变。这就实现了动态修改操作。
Mapper接口
public interface UserMapper {
void updateUser(User user);
}
Mapper.xml
<update id="updateUser" parameterType="com.example.model.User">
UPDATE users
<set>
<if test="name != null">name = #{name},</if>
<if test="age != null">age = #{age},</if>
<if test="email != null">email = #{email},</if>
</set>
WHERE id = #{id}
</update>
四、删除功能
1、删除单个
// 创建UserMapper接口
public interface UserMapper {
void deleteUserById(int id);
}
// 在Mapper.xml文件中定义deleteUserById的SQL语句
<delete id="deleteUserById" parameterType="int">
DELETE FROM users
WHERE id = #{id}
</delete>
// 在代码中调用deleteUserById方法进行删除
int userId = 1;
userMapper.deleteUserById(userId);
2、批量删除
- mybatis会将数组参数封装为一个Map集合,所以需要foreach来遍历
- 1、默认:array=数组
- 2、使用@Param注解来改变map集合的默认key的名称
- 在下列示例中,我们创建了一个UserMapper接口,其中定义了一个batchDeleteUser方法,接受一个List<Integer>类型参数表示需要删除的用户ID列表。在Mapper.xml文件中,我们定义了batchDeleteUser的SQL语句,使用了MyBatis的foreach标签来循环遍历用户ID列表,并将每个ID作为参数传入SQL语句中的IN条件中,从而实现批量删除操作。
// 创建UserMapper接口
public interface UserMapper {
void batchDeleteUser(List<Integer> userIds);
}
// 在Mapper.xml文件中定义batchDeleteUser的SQL语句
<delete id="batchDeleteUser" parameterType="java.util.List">
DELETE FROM users
WHERE id IN
<foreach collection="list" item="userId" open="(" separator="," close=")">
#{userId}
</foreach>
</delete>
// 在代码中调用batchDeleteUser方法进行批量删除
List<Integer> userIds = Arrays.asList(1, 2, 3);
userMapper.batchDeleteUser(userIds);
参数传递
Mybatis接口方法对 接收到的不同的参数 用ParamNameResolver类 进行 不同的封装处理
单个参数:
- 1、POJO类型:直接使用,属性名和参数占位符名称一致
- 2、Map集合:直接使用,键名和参数占位符名称一致
- 3、Collection:封装成Map集合
- map.put("arg0",collection集合);
- map.put("collection",collection集合);
- 4、List:封装成Map集合
- map.put("arg0",list集合);
- map.put("collection",list集合);
- map.put("list",list集合);
- 5、Array:封装成Map集合
- map.put("arg0",数组);
- map.put("array",数组);
- 6、其他类型
多个参数
封装成Map集合
User select(@Param("username")String username,String password);
封装成Map集合后,建议使用@Param注解,替换Map集合中默认的键名,并使用修改后的名称来获取值,提高可读性
MyBatis常见问题
- SQL映射文件的警告,无法识别表信息
- 解决:在idea中配置mysql数据库连接
- 实体类属性名和数据库表列名不一致,不能自动封装数据
- 解决:使用<resultMap>
- 使用参数占位符${}时,会存在sql注入问题
- 解决:使用#{}
- SQL语句中的特殊字符报错,比如"<"
- 解决:使用转义字符,比如"<"表示"<"