一. MyBatis 的CRUD操作
1:添加操作
略(在1中末尾有体现)
2:删除操作
根据学号删除一条学生信息
步骤:
在StudentDAO中定义删除方法
在StudentMapper.xml中对接口方法进行"实现"(插件可以生成)
测试:在StudentDAO的测试类中添加测试方法
try {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
//SqlSessionFactory表示mybatis的会话工厂,工厂模式
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
//SqlSession 对象是mybatis和数据库之间的连接,也就是会话,创建了连接,可以得到所有的mapper对象(映射关系)
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过SqlSession 对象调用getMapper方法获取DAO接口对象
StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);
//调用被测试方法
int i = studentDAO.deleteStudent("10001");
//提交事务
sqlSession.commit();
System.out.println(i);
} catch (IOException e) {
e.printStackTrace();
}
}
3.修改操作
根据学号,修改其他字段信息
<update id="updateStudent">
update tb_students
set
stu_name = #{stuName},
stu_gender = #{stuGender},
stu_age = #{stuAge}
where
stu_num = #{stuNum}
</update>
@Test
public void testUpdateStudent(){
try {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = builder.build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();
StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);
int i = studentDAO.updateStudent(new Student(2,"10002","can","男",18));
sqlSession.commit();
assertEquals(1,i);//期望,单元测试的期望返回结果
System.out.println(i);
} catch (IOException e) {
e.printStackTrace();
}
}
assertEquals(1,i)
如果两者一致, 程序继续往下运行.
如果两者不一致, 中断测试方法, 抛出异常信息 AssertionFailedError .
4.查询操作-查询所有
- 在studentDAO接口中定义方法,返回多条,所以用List集合来装
- 在studentMapper文件中写
下面为两种实现方案:法一取别名,法二用resultMap
<!-- resultType执行查询结果,封装的对象的实体类-->
<!-- resultSets指定当前操作返回的集合类型(可省略)-->
<!-- resultType返回的类型-->
<!-- <select id="listStudents" resultType="com.liguoqing.pojo.Student" resultSets="java.util.List">-->
<!-- select-->
<!-- sid as stuId,-->
<!-- stu_num as stuNum,-->
<!-- stu_name as stuName,-->
<!-- stu_gender as stuGender,-->
<!-- stu_age as stuAge-->
<!-- from tb_students-->
<!-- </select>-->
<!--resultMap标签用于定义实体类和数据表的映射关系(ORM)-->
<resultMap id="studentMap" type="com.liguoqing.pojo.Student">
<id column="sid" property="stuId"/>
<result column="stu_num" property="stuNum"/>
<result column="stu_name" property="stuName"/>
<result column="stu_gender" property="stuGender"/>
<result column="stu_age" property="stuAge"/>
</resultMap>
<!-- resultMap 用于引用一个实体的映射关系,当配置了resultMap以后,resultType就可以省略-->
<select id="listStudents" resultMap="studentMap">
select sid,
stu_num,
stu_name,
stu_gender,
stu_age
from tb_students
</select>
这里resulttype就可以不写了,因为map里已经有了
这里直接复制数据库的
- test方法里面写
@Test
public void testStudentList() {
try {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = builder.build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();
StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);
List<Student> studentList = studentDAO.listStudents();
assertNotNull(studentList);
sqlSession.commit();
for (Student student : studentList
) {
System.out.println(student);
}
} catch (IOException e) {
}
}
最终得到结果
5.查询操作-查询一条记录
根据学号查询一个学生信息
和上文同样的方法
几个注意点:
- 多个查询操作可以使用同一个map
- 查询不需要提交事务
- 牢记三部曲-在StudentDAO中定义接口方法;用插件+自己写的mysql语句在StudentDAOMappperxml 中配置StudentDAO接口的方法实现–SQL;写单元测试
6.查询操作-多参数查询
参数 start ,pagesize
在StudentDAO中定义操作方法,如果方法有多个参数,使用@Param 注解声明参数的别名
package com.liguoqing.dao;
public interface StudentDAO {
/*
* 在MyBatis进行操作:
* 1:如果操作方法只有一个简单类型或者字符串类型的参数,
* 在Mapper配置中可以直接通过#{key}获取,这个key的占位符号可以随便写
* 2:如果操作方法有一个对象类型的参数,
* 在Mapper配置中可以直接通过#{attrName}获取对象的指定属性值(attrName必须是参数对象的属性)
* 3:如果操作方法有一个Map类型的参数,
* 在Mapper配置中可以直接通过#{key}获取key的指定value值
* 4:如果操作方法有多个参数,该如何处理呢?
* 通过MyBatis自带的参数 arg0 arg1 .. 来获取相应的参数
* 也可以通过@Param("key") 给参数添加注解的方式
*/
public int insertStudent(Student student);
public int deleteStudent(String stuNum);
public int updateStudent(Student student);
public List<Student> listStudents();
public Student queryStudent(String stuNum);
// public List<Student> listStudentsByPage(HashMap<String,Integer> map);
// public List<Student> listStudentsByPage(int start,int pageSize);
public List<Student> listStudentsByPage(@Param("start") int start
,@Param("pageSize") int pageSize);
}
在StudentMapper.xml配置sql时,使用#{}获取到指定的参数
<select id="listStudentsByPage" resultMap="studentMap">
select sid,
stu_num,
stu_name,
stu_gender,
stu_age
from tb_students
limit #{start}, #{pageSize}
<!-- limit #{arg0}, #{arg1}-->
<!-- limit #{param1}, #{param2}-->
</select>
—注意:如果DAO操作方法,没有通过@Param指定参数别名,在SQL中也可以通过MyBatis自带的arg0 ,arg1… 或者 param1,param2…获取参数
单元测试
@Test
public void testlistStudentsByPage() {
try {
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = builder.build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();
StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);
// HashMap<String,Integer> map = new HashMap<String,Integer>();
// map.put("start",0);
// map.put("pageSize",2);
// List<Student> studentList = studentDAO.listStudentsByPage(map);
List<Student> studentList = studentDAO.listStudentsByPage(0,2);
assertNotNull(studentList);
sqlSession.commit();
for (Student student : studentList
) {
System.out.println(student);
}
} catch (IOException e) {
}
}
7.查询操作-查询总记录数
StudentDAO
public int getCount();
在StudentMapper.xml配置sql时,使用 resultType 指定当前操作的返回类型为int(插件自动生成java.lang.Integer也没问题)
<select id="getCount" resultType="int">
select count(1) from tb_students
</select>
单元测试
@Test
public void testGetStudentCount(){
try{
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = builder.build(is);
SqlSession sqlSession = sqlSessionFactory.openSession();
StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);
int i = studentDAO.getCount();
System.out.println(i);
}catch (IOException e){
}
}
8.添加操作回填生成的主键
在StudentMapper.xml
在insert标签中 useGeneratedKeys 设置添加操作是否需要回填生成的主键 keyProperty 设置回填的位置
<!--parameterType 这个参数在DAO中已经指定类型了,在这里可以省略-->
<!-- useGeneratedKeys 设置添加操作是否需要回填生成的主键-->
<!-- keyProperty 设置回填的位置-->
<insert id="insertStudent" parameterType="com.liguoqing.pojo.Student" useGeneratedKeys="true" keyProperty="stuId">
insert into tb_students(stu_num, stu_name, stu_gender, stu_age)
values (#{stuNum}, #{stuName}, #{stuGender}, #{stuAge})
</insert>
二.MyBatis工具类封装
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 MyBatisUtil {
private static SqlSessionFactory factory;//单例的
private static final ThreadLocal<SqlSession> local = new ThreadLocal<SqlSession>(); //线程锁,各个线程之间不影响,例如开启关闭数据库连接之类的
static {
try {
//加载myBatis配置文件,创建会话工厂
factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
} catch (IOException e) {
e.printStackTrace();
}
}
//得到sqlSession对象
public static SqlSession getSqlSession() throws IOException {
SqlSession sqlSession = local.get();
if (sqlSession == null){
sqlSession = factory.openSession();
local.set(sqlSession);
}
return sqlSession;
}
public static <T extends Object>T getMapper(Class<T> C) throws IOException {
SqlSession sqlSession = getSqlSession();
T dao = sqlSession.getMapper(C);
return dao;
}
public static SqlSessionFactory getFactory() throws IOException {
if (factory == null){
factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
}
return factory;
}
}
这样就可以简短的写测试内容
三.事务管理
sqlSession对象的作用:
- getMapper(DAO.class) 获取Mapper(DAO接口的实例)
- 事务管理
1:手动提交事务
sqlSession .commit() 提交事务
sqlSession.rollback() 事务回滚
@Test
public void insertStudent() {
try {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
//1:当我们获取sqlSession对象时,就默认开启了事务
try{
StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);
Student student = new Student(0, "10005", "java少年", "男", 24);
int i = studentDAO.insertStudent(student);
//2:操作完成并成功以后,需要手动提交
sqlSession.commit();
System.out.println(student);
System.out.println(i);
}catch (Exception e){
//3:当操作出现异常,调用rollback进行回滚
sqlSession.rollback();
}
} catch (IOException e) {
e.printStackTrace();
}
}
2:自动提交事务
sqlSession = factory.openSession(true);//这里的参数,如果不填,默认是false,也就是需要手动进行提交,如果填了true会自动提交事务
待补
四.MyBatis主配置文件
mybatis-config.xml 是MyBatis框架的主配置文件,主要用于配置MyBatis数据源以及工作属性信息
注意:
标签使用时需要注意顺序
空标签会导致报错
7. 配置文件详解
7.1 properties
可以使用properties读取properties配置文件。使用其中的resource属性来设置配置文件的路径。
然后使用${key}来获取配置文件中的值
例如:
在resources目录下有jdbc.properties文件,内容如下:
jdbc.url=jdbc:mysql://localhost:3306/mybatis_db
jdbc.driver=com.mysql.jdbc.Driver
jdbc.username=root
jdbc.password=root
在mybatis-config.xml中:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--设置配置文件所在的路径-->
<properties resource="jdbc.properties"></properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--获取配置文件中配置的对应的值来设置连接相关参数-->
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
</configuration>
7.2 settings
可以使用该标签来设置进行一些设置
例如:
<settings>
<!--开启自动驼峰命名映射-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
具体的设置参考:https://mybatis.org/mybatis-3/zh/configuration.html#settings
7.3 typeAliases
可以用来设置给全类名设置别名,简化书写。一般设置一个包下的类全部具有默认别名。默认别名是类目首字母小写。例如:com.sangeng.pojo.User别名为user
<typeAliases>
<package name="com.sangeng.dao"></package>
</typeAliases>
7.4 environments
配置数据库相关的环境,例如事物管理器,连接池相关参数等。
<!--设置默认环境-->
<environments default="development">
<!--设置该环境的唯一标识-->
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--获取配置文件中配置的对应的值来设置连接相关参数-->
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
7.5 mappers
该标签的作用是加载映射的,加载方式有如下几种(主要使用第四种):
①使用相对于类路径的资源引用,例如:
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
②使用完全限定资源定位符(URL),例如:
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
③使用映射器接口实现类的完全限定类名,例如:
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
④将包内的映射器接口实现全部注册为映射器,例如:
<!-- 定义dao接口所在的包。要求xml文件存放的路径和dao接口的包名要对应 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
此时对应包下所有xml映射文件都能找到
8. 打印日志
①log4j配置 在resources目录下创建log4j.properties文件:
在Create resource bundle的弹出框中,在Resource bundel base name的输入框中填写资源文件的名称,不要带properties后缀,例如:validatemessage,其余都默认设置,点击OK按钮后就可以在resources文件夹中新增了一个validatemessage.properties文件
内容如下:
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c:/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=debug, stdout
②引入依赖
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
看这些是最重要的
9.获取参数时 #{}和${}的区别
如果使用#{}.他是预编译的sql可以防止SQL注入攻击
如果使用${}他是直接把参数值拿来进行拼接,这样会有SQL注入的危险
如果使用的是#{}来获取参数值日志如下:
Preparing: select * from user where id = ? and username = ? and age = ? and address = ?
Parameters: 2(Integer), 快乐风男(String), 29(Integer), 北京(String)
如果使用${}来获取参数值日志如下:
Preparing: select * from user where id = 2 and username = 快乐风男 and age = 29 and address = 北京