MyBatis连接数据库的详细操作
最近学习一下Maven的使用,发现是真的香,然后顺带就学到了SSM这个熟悉的身影中的MyBatis这个持久层框架。这是我第一次使用框架来学习java,感觉难度瞬间就上去了,别说懂原理,就是基本使用都花了好几天反复看教程才调试通,留下了菜鸡的泪水QAQ。。不过有一说一,框架确实方便了开发,废话不多说,看看具体的流程吧
一、Mybatis连接数据库
1、简单连接的流程
- 连接数据库,导入jar包依赖(pom.xml)
这里用Maven来部署文件
<!--pom.xml中导入依赖-->
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
这里是在核心配置文件的设置,完整代码在后面有
<!--property属性可以通过外部properties文件导入-->
<properties resource="db.properties" />
<!--mybatis.xml中配置数据库信息-->
<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>
这里的JDBC连接操作应该都很熟了
#db.properties
#url配置时区和字符集
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/xx?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT
username=xxx
password=xxxx
- 建造工具类(MybatisUtils.java)
//MyBatis官方给出的代码
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
/**
* 工具类
* SQLSession的创建写在静态代码块里
* 程序执行时就创建出来一个SqlSession对象
*/
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 返回一个SQLSession(建议还是不要自动提交,防止出错也保存到数据库中)
* @return 设置true,自动提交
*/
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession(true);
}
}
- 编写核心配置文件(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="db.properties" />
<!--
建立连接
这里的default属性是为了适配不同环境,使用不同的数据库连接(如测试环境、发布环境等)
default在id中取值
事务处理方式(transactionManager):JDBC事务处理模式(commit,rollback,close)
连接类型(dataSource):POOLED,连接池模式(连接可回收,用完了放回池子里)
-->
<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>
<environment id="test">
<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 信息后,MyBatis才知道去哪里加载 Mapper映射文件-->
<mappers>
<mapper resource="com/qs/map/StudentMapper.xml"/>
</mappers>
</configuration>
- 编写实体类(Student.java)
这里就不写代码了,无非就是构造方法和getter和setter方法
- 编写接口(StudentMapper.java)
public interface StudentMapper {
List<Student> getStudentList();
/**
* 注解实现CRUD
* 方法有多个参数,要在参数前加上@Param注解
*/
@Select("select * from student where id = #{id}")
Student getStudentById(@Param("id") int id);
int addStudent(Student student);
int updateStudent(Student student);
int deleteStudent(int id);
}
- 和接口在同一目录下编写Mapper映射配置文件(StudentMapper.xml)
namespace、id、resultType等的配置
然后不同语句在mapper中的不同的标签中执行,、…
<?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">
<mapper namespace="com.qs.map.StudentMapper">
<!--设置resultMap来映射实体类到数据库的字段-->
<resultMap id="StudentMap" type="Student">
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="email" property="email"/>
<result column="age" property="age"/>
</resultMap>
<!--下面执行SQL语句-->
<select id="getStudentList" resultType="student" resultMap="StudentMap">
select * from student
</select>
<!--
前面用了注解的方式来完成SQL语句,这里就不用写了
<select id="getStudentById" parameterType="int" resultType="student">
select * from student where id = #{id}
</select>
-->
<insert id="addStudent" parameterType="student">
insert into student (id,name,email,age) values (#{id},#{name},#{email},#{age})
</insert>
<update id="updateStudent" parameterType="student" >
update student set name=#{name},email=#{email},age=#{age} where id = #{id}
</update>
<delete id="deleteStudent" parameterType="int">
delete from student where id = #{id}
</delete>
</mapper>
- 编写测试文件实现接口的方法(可使用@Test注解来测试Mapper接口的方法)
//使用@Test注解要在pom.xml中添加junit依赖
//用@Test注解可以不用main方法也可以执行
public class StudentMapperTest {
@Test
public void test() {
SqlSession sqlSession=null;
try {
sqlSession = MybatisUtils.getSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
List<Student> studentList = studentMapper.getStudentList();
for (Student stu : studentList) {
System.out.println(stu);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
@Test
public void getStudentById() {
SqlSession sqlSession=null;
try {
sqlSession = MybatisUtils.getSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student student = studentMapper.getStudentById(2);
System.out.println(student);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
@Test
public void addStudent(){
SqlSession sqlSession = null;
try {
sqlSession = MybatisUtils.getSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
int result = studentMapper.addStudent(new Student(4,"哈哈","aaa@qq.com",22));
if (result>0) {
System.out.println("添加成功!");
}
//增删改操作一定要提交事务
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
@Test
public void updateStudent() {
SqlSession sqlSession = null;
try {
sqlSession = MybatisUtils.getSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
int result = studentMapper.updateStudent(new Student(4,"嘿嘿","121212",18));
if (result>0) {
System.out.println("修改成功!");
}
//增删改操作一定要提交事务
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
@Test
public void deleteStudent() {
SqlSession sqlSession = null;
try {
sqlSession = MybatisUtils.getSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
int result = studentMapper.deleteStudent(4);
if (result == 1) {
System.out.println("删除成功!");
}
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
assert sqlSession != null;
sqlSession.close();
}
}
}
- 修改pom.xml,设置资源过滤器(防止Maven导出资源失败)(可选)
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
2、常见问题(各种bug)
这些问题忘了把具体的问题保存下来了,只记得找到的一些解决办法,后面再遇到再完善
-
配置文件没有注册、绑定接口错误
(多半是映射配置文件名错了)检查核心配置文件中是否配置mapper映射)
配置文件中的mapper标签一定要仔细观察,很多时候错误都是mapper没有配置好
-
方法名不对
-
返回类型不对
-
Maven导出资源问题(设置资源过滤器)
二、Mybatis三个核心接口(使用不当会造成并发问题)
1、SqlSessionFactoryBuilder(局部作用域)
用来创建多个SQLSessionFactory实例,一旦创建,SQLSessionFactoryBuilder就丢弃了
2、SqlSessionFactory(应用作用域)
简单说就是数据库连接池,被创建出来就一直存在可以使用
建议不要重复创建,会造成资源浪费
3、SqlSession(对象)
线程不安全,最好放在一个方法中
每次收到的HTTP请求,就可以打开一个SQLSession,
返回一个响应,就可以关闭它(关闭放在finally中执行)
每个SQLSession可以对应多个Mapper,每个Mapper对应一个业务
三、一些操作
1、CRUD操作(增删查改)
1、namespace
包名要和Mapper接口的包名一致
2、select
id:就是对应的namespace中接口的方法名
…
2、给实体类起别名(typeAliases)
方式一:(这种方式的别名是自定义的)
<typeAliases>
<typeAlias type="全类名" alias="别名"/>
</typeAliases>
方式二:(这种方式的别名是类名,建议首字母小写,但是可以用注解起别名)
<typeAliases>
<package name="包名"/>
</typeAliases>
3、映射器常见配置(mapper)
数据库配置文件外部引入实体类别名
保证Mapper接口和Mapper.xml名字一致,并且在同一个包下
4、解决属性名和字段名不一致的问题
暴力解决(SQL起别名)
resultMap(结果集映射)
四、日志
1、常见的工具
log4j
stdout_logging
2、核心配置文件中设置日志
<!--如果是log4j,则需要导入log4j的jar包,并配置一个log的属性文件-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
数据库配置文件外部引入实体类别名
保证Mapper接口和Mapper.xml名字一致,并且在同一个包下
4、解决属性名和字段名不一致的问题
暴力解决(SQL起别名)
resultMap(结果集映射)
四、日志
1、常见的工具
log4j
stdout_logging
2、核心配置文件中设置日志
<!--如果是log4j,则需要导入log4j的jar包,并配置一个log的属性文件-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>