<configuration>
<properties resource="druid.properties" />
<environments default="mysql_mybatis">
<environment id="mysql_mybatis">
<transactionManager type="jdbc"/>
<dataSource type="pooled">
<property name="driver" value="${DriverClassName}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
dataSource>
environment>
environments>
configuration>
其中mybatistest是我数据库的名字,大家可以自行更改。
DriverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatistest?useSSL=true&serverTimezone=GMT
username=root
password=293911
initialSize=5
maxActice=10
maxWait=3000
像之前的DButils一样,用于获取连接,这里获取的是mybatis的SqlSession连接,一般写好后不用怎么改了,通用的。
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.Reader;
import java.sql.Connection;
public class MybatisUtil {
private static ThreadLocal<SqlSession> threadlocal = new ThreadLocal<SqlSession> ();
private static SqlSessionFactory sqlSessionFactory;
static {
try {
/**
*每 一 个 MyBatis 的 应 用 程 序 都 以 一 个 SqlSessionFactory 对 象 的 实 例 为 核 心 。
SqlSessionFactory 对 象 的 实 例 可 以 通 过 SqlSessionFactoryBuilder 对 象 来 获 得 。
SqlSessionFactoryBuilder 对象可以从 XML 配置文件,
或从 Configuration 类的习惯准备的实例中构建 SqlSessionFactory 对象。
*/
//读取xml文件
Reader reader = Resources.getResourceAsReader("mybatis.xml");
//构建工厂类
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
}
catch (Exception e){
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* 禁止new出来
*/
private MybatisUtil(){}
/**
* 获取SQLSession
* @return
*/
public static SqlSession getSqlSession(){
//从当前线程获取SQLSession对象,可以从当前线程获取也可以从工厂类获取
SqlSession sqlSession = threadlocal.get();
if (sqlSession==null){
sqlSession = sqlSessionFactory.openSession();
//绑定当前线程
threadlocal.set(sqlSession);
}
return sqlSession;
}
/**
* 关闭连接对象
*/
public static void closeSqlSession(){
SqlSession sqlSession = threadlocal.get();
if (sqlSession!=null){
sqlSession.close();
//解绑线程目的是让gc快回收。
threadlocal.remove();
}
}
/**
* 测试能否获取连接,首先确保数据库已存在!
* @param args
*/
public static void main(String[] args) {
Connection connection = MybatisUtil.getSqlSession().getConnection();
System.out.println(connection!=null?"success":"false");
}
}
1. 新建数据库mybatistest
2. 创建students表(id,name,sal)
3. 运行mybatis工具类的主函数
CREATE DATABASE mybatisTest;
CREATE TABLE students( id INT(5) PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(10), sal DOUBLE(8,2) );
用来写sql语句并对结果进行封装。
<mapper namespace="np_Student">
<resultMap id="StudentMap" type="model.Student">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sal" column="sal"/>
resultMap>
<insert id="add" parameterType="model.Student">
insert into students values(#{id},#{name},#{sal});
insert>
mapper>
然后将写好的mapper配置文件添加到一开始写的mybatis配置文件中去,即在mybatis.xml的/configuration标签上面去。
<mappers>
<mapper resource="StudentMapper.xml" />
mappers>
1. 创建model包,在model包中新建student类
2. 创建dao包,在dao包中新建add(Student student)方法
package model;
public class Student {
private Integer id;
private String name;
private Double sal;
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", sal=" + sal +
'}';
}
public Student() {
}
public Student(Integer id, String name, Double sal) {
this.id = id;
this.name = name;
this.sal = sal;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getSal() {
return sal;
}
public void setSal(Double sal) {
this.sal = sal;
}
}
package dao;
import model.Student;
public interface StudentDao {
public void add(Student student);
}
package dao;
import model.Student;
import org.apache.ibatis.session.SqlSession;
import utils.MybatisUtil;
public class StudentDaoImpl implements StudentDao {
@Override
public void add(Student student) {
SqlSession sqlSession = null;
try {
//获取sqlSession对象
sqlSession = MybatisUtil.getSqlSession();
/**
* 调用插入方法。
* insert方法的参数有两个:
* String s = 命名空间.方法名(id名)
* Object o = 参数列表。
* commit方法参数有true/false,默认为true
* 需要我们手动提交事务。
*/
sqlSession.insert("np_Student.add",student);
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
//事务回滚
sqlSession.rollback();
throw e;
}finally {
MybatisUtil.closeSqlSession();
}
}
}
完成上面步骤后我们就基本上可以用mybatis连接到数据库并会进行一定的操作了,下面我们将使用mybatis进行数据库的增删改查。
所有的执行语句的方法,提交或回滚事务都由这个实例来进行操作。
由于我们student表id是自增的,所以我们可以不设置id属性,使用mybatis的useGeneratedKeys方法来进行改进添加数据。
<insert id="add" parameterType="model.Student" useGeneratedKeys="true" keyProperty="id">
insert into students(name,sal) values(#{name},#{sal});
insert>
在StudentMapper.xml中添加select标签,然后在dao类中添加findStuById(int id)接口,
最后在dao实现类中实现findStuById方法;
<select id="findStuById" parameterType="int" resultMap="StudentMap">
select * from students where id = #{id};
select>
说明一下:MyBatis 中parameter是非常强大的元素,上面的这个示例说明了一个非常简单的命名参数映射。
参数类型被设置为“int” ,因此这个参数可以被设置成任何内容。原生的类型或简单数据类型,
比如整型和没有相关属性的字符串,因此它会完全用参数来替代。对于复杂的参数类型如student类,
它会自动查找相关属性,并将它们的值传递到预处理语句的参数中去。
public Student findStuById(int id);
@Override
public Student findStuById(int id) {
SqlSession sqlSession = MybatisUtil.getSqlSession();
try {
return sqlSession.selectOne("np_Student.findStuById",id);
}catch (Exception e){
e.printStackTrace();
throw e;
}finally {
MybatisUtil.closeSqlSession();
}
}
在StudentMapper.xml中添加select标签,然后在dao类中添加findAll()接口,最后在dao实现类中通过SQLSession.selectList()方法,实现findAll()方法;
<select id="findAll" resultMap="StudentMap">
select * from students;
select>
public List<Student> findAll();
@Override
public List<Student> findAll() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
try{
List<Student> students = sqlSession.selectList("np_Student.findAll");
return students;
}catch (Exception e){
e.printStackTrace();
}finally {
MybatisUtil.closeSqlSession();
}
return null;
}
在StudentMapper.xml中添加标签,然后在dao类中添加delStudent(int id)接口,最后在dao实现类中实现delStudent方法;
<delete id="delStudent" parameterType="int">
delete from students where id = #{id};
delete>
public Student DelStuById(int id);
@Override
public Student DelStuById(int id) {
SqlSession sqlSession = MybatisUtil.getSqlSession();
Student stuById = null;
try {
//查询所删除的数据。
stuById = sqlSession.selectOne("np_Student.findStuById",id);
//删除对应id的数据。
sqlSession.delete("np_Student.delStudent",id);
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
sqlSession.rollback();
}finally {
MybatisUtil.closeSqlSession();
}
return stuById;
}
在StudentMapper.xml中添加标签,然后在dao类中添加updateStudent(Student student)接口,最后在dao实现类中实现updateStudent(Student student)方法;
<update id="updateStudent" parameterType="model.Student">
update students set name=#{name},sal=#{sal} where id=#{id};
update>
public void updateStudent(Student student);
@Override
public void updateStudent(Student student) {
SqlSession sqlSession = MybatisUtil.getSqlSession();
try {
sqlSession.update("np_Student.updateStudent",student);
//对于增删改操作都需要我们手动提交事务,不然操作是不会成功的。
sqlSession.commit();
}catch (Exception e){
e.printStackTrace();
sqlSession.rollback();
}finally {
MybatisUtil.closeSqlSession();
}
}
分页是指查询数据库一定区间范围内的所有数据,sql语句:select * from students limit 0,5;表示从第0行开始,查询5条数据。
<select id="pagination" parameterType="Map" resultMap="StudentMap">
select * from students limit #{start},#{count};
select>
public List<Student> pagination(int start, int count);
@Override
public List<Student> pagination(int start, int count) {
SqlSession sqlSession = MybatisUtil.getSqlSession();
try {
Map<String,Integer> map = new HashMap<>();
map.put("start",start);
map.put("count",count);
//由于参数只能传递一个,所以我们使用map集合,到时候通过key取值。
List<Student> students = sqlSession.selectList("np_Student.pagination", map);
return students;
}catch (Exception e){
e.printStackTrace();
}finally {
MybatisUtil.closeSqlSession();
}
return null;
}
MyBatis 的一个强大的特性之一通常是它的动态 SQL 能力。如果你有使用 JDBC 或其他相似框架的经验,
你就明白条件地串联 SQL 字符串在一起是多么的痛苦,确保不能忘了空格或在列表的最后省略逗号。
动态 SQL 可以彻底处理这种痛苦。
通常使用动态 SQL 不可能是独立的一部分,MyBatis 当然使用一种强大的动态 SQL 语言来改进这种情形,
这种语言可以被用在任意映射的 SQL 语句中。 动态 SQL 元素和使用 JSTL 或其他相似的基于 XML 的文本处理器相似。
在动态 SQL 中所做的最通用的事情是包含部分 where 字句的条件。比如: 多条件查询。
<select id="findByCondition" resultMap="StudentMap" parameterType="Map">
select * from students
<where>
<if test="name!=null">
and name=#{name};
if>
where>
select>
看到这里不知道大家是不是有点疑问呢?我们在JSTL中一般都是用EL表达式如
于是我就想是不是跟map的键有关?为了验证这个想法,我就写了这么一个测试类。
为了更清楚的看出效果,首先将标签里面的"name"改为"mapname"。
<select id="findByCondition" resultMap="StudentMap" parameterType="Map">
select * from students
<where>
<if test="mapname!=null">
and name=#{mapname};
if>
where>
select>
@Test
public void test() {
HashMap<String, Object> map = new HashMap<>();
map.put("name","lisi");
SqlSession sqlSession = MybatisUtil.getSqlSession();
List<Student> students = sqlSession.selectList("np_Student.findByCondition", map);
System.out.println(students);
}
[Student{id=1, name='lisi', sal=11.0}, Student{id=2, name='lee', sal=22.0}, Student{id=3, name='zhangsan', sal=1200.0}]
我数据库里面的所有数据都被取了出来,说明了执行findBYCondition方法并没有拼接name=“lisi”;
将其更改为map.put(“mapname”,lisi),注意这里的mapname和我们的findBYCondition方法里面定义的
if标签名字对应,如果这次能查询出"lisi"这条记录,说明if标签里面定义的正是参数map的键的名字。
@Test
public void test() {
HashMap<String, Object> map = new HashMap<>();
map.put("mapname","lisi");
SqlSession sqlSession = MybatisUtil.getSqlSession();
List<Student> students = sqlSession.selectList("np_Student.findByCondition", map);
System.out.println(students);
}
[Student{id=1, name='lisi', sal=11.0}]
可以证实,标签里面定义的就是map集合的键名。
跟switch用法差不多。
<select id="choose" parameterType="map" resultMap="StudentMap">
select * from students
<where>
<choose>
<when test="name!=null">
and name = #{name}
when>
<otherwise>
and id = #{id}
otherwise>
choose>
where>
select>
修剪元素,很强大,我们之所以可以如此方便的使用动态sql,它功不可没。
比如:where 元素知道如果由被包含的标记返回任意内容,就仅仅插入"where" 。
而且,如果以"and "或"or"开头的内容,那么就会跳过 where 不插入。
如果 where 元素没有做出你想要的,你可以使用 trim 元素来自定义。
比如,和 where 元素相等的 trim 元素是:
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
trim>
自己定义一个trim标签。
<select id="findByCondition" resultMap="StudentMap" parameterType="Map">
select * from students
<trim prefix="where" prefixOverrides="1=1 ">
<if test="name!=null">
1=1 name=#{name};
if>
trim>
select>
于where相同的还有set,同样可以用trim标签进行操作。
foreach操作是迭代一个集合, 通常是构建在 in 条件中的。
例子:批量查询
<select id="findStuByIDs" resultMap="StudentMap" parameterType="List">
select * from students where id in
<foreach collection="list" open="(" close=")" separator="," item="item">
#{item}
foreach>
select>
模糊查询的sql语句:select* from students where name like %name%;
<select id="findByLike" parameterType="map" resultMap="StudentMap">
select * from students
<where>
<if test="name!=null">
<bind name="newname" value="'%'+name+'%'"/>
and name like #{newname}
if>
<if test="sal!=null">
<bind name="newsal" value="'%'+sal+'%'"/>
and sal like #{newsal}
if>
where>
select>
set 元素可以被用于动态包含更新的列,而不包含不需更新的
<update id="updateIfNecessary" parameterType="model.Student">
update students
<set>
<if test="name!=null">
name=#{name},
if>
<if test="sal!=null">
sal=#{sal},
if>
set>
where id = #{id};
update>
<delete id="delStuInList" parameterType="List">
delete from students where id in
<foreach collection="list" open="(" close=")" separator="," item="item">
#{item}
foreach>
delete>
说实话,这里我有点懵,在网上看别人动态插入的代码很长很长的一段,又拼接key,又拼接value,是怕担心顺序乱了?
其实我们只要保证顺序一致,就可以不用拼接和判断是否为空了。
<insert id="dynamicInsert" parameterType="model.Student" useGeneratedKeys="true" keyProperty="id">
insert into students values
<trim prefix="(" suffix=")" suffixOverrides=",">
#{id},#{name},#{sal}
trim>
insert>
当我们在设置Mapper文件的时候,需要指定parameterType属性或者resultType属性,
该属性值如果不是一般的类型或String类型,比如是对象类型的话,就需要指定全类名,
如果有多个SQL映射语句的话,那么每次都指定全类名的话,可能会比较麻烦,是否有更好的方法,
可以简化一下。你可以通过设置别名的方式来简化。
<typeAliases>
<typeAlias type="model.Student" alias="Student"/>
typeAliases>
之后我们再对parameterType属性赋值时可以直接用别名就会方便很多。
<insert id="dynamicInsert" parameterType="Student" useGeneratedKeys="true" keyProperty="id">
insert into students values
<trim prefix="(" suffix=")" suffixOverrides=",">
#{id},#{name},#{sal}
trim>
insert>
1. sql写在xml里,便于统一和管理,解除了sql与程序代码的耦合。
2. Mybatis的事务是默认开启的,我们需要手动提交事务。
3. 写Mapper.xml映射文件时,更像在写对应的CURD方法,id(方法名),parameterType(传入参数),resultMap(返回值)。
如果文章有错的地方欢迎指正,大家互相交流。
最后,码字不易,喜欢点个赞呀!