<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `user` VALUES ('1', 'tom', '11');
INSERT INTO `user` VALUES ('2', 'jack', '12');
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>
<!-- environments 配置多个environment,供切换 -->
<environments default="development"> <!--default指定一个默认环境的id-->
<environment id="development">
<!— type:处理事务方式, 大多数情况使用jdbc,另一种 managed:将事物交给其他组件托管,如spring-->
<transactionManager type="JDBC" />
<!-- 配置数据库连接类型
POOLED:常用的简单的JDBC配置,使用了连接池
UNPOOLED:不使用连接池,每次均需要打开和关闭数据连接,很消耗性能,相当于DriverManager.getConnection(url,username,password)
JDNI:从tomcat中获取一个内置的数据库连接池
-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=utf-8" />
<property name="username" value="账号" />
<property name="password" value="密码" />
</dataSource>
</environment>
</environments>
<mappers>
<!-- package 注册包下面的所有Mapper接口 -->
<!-- <package name="com.xxx.xxx.mapperinterface"/> -->
<!-- resource属性 注册单个相对于类路径的Mapper.xml文件 -->
<!-- <mapper resource="com/xxx/mybatis/mapper/UserMapper.xml"/> -->
<!-- url属性 注册一个绝对路径的的Mapper.xml文件 -->
<!-- <mapper url="file:///E:/UserMapper.xml"/> -->
<!-- class属性 注册一个Mapper接口,接口必须与mapper.xml文件名同名,且同路径下 -->
<!-- <mapper class="com.xxx.xxx.mapperinterface.UserMapper"/> -->
</mappers>
</configuration>
创建实体类User.java
public class User {
private int id;
private String name;
private int age;
//toString、全参构造、无参构造、set、get、toString全部省略。。。
}
创建session工具类
做一个util包,放工具类,以后直接调用静态方法获取Session
SqlSession session = MyBatisUtil.getSqlSession();
public class MyBatisUtil {
public static SqlSessionFactory getSqlSessionFactory() throws IOException{
String resource = "mybatis的xml配置文件名";
InputStream is = Resources.getResourceAsStream(resource);//使用类加载器加载mybatis的配置文件
//构建sqlSession的工厂 build方法还可以追一个参数,指定环境environment标签的id
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
return sqlSessionFactory;
}
public static SqlSession getSqlSession() throws IOException{
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
return sqlSessionFactory.openSession();//若是设置为opsenSession(true)默认自动提交
}
}
另一种写法
public class MyBatisUtil {
private static SqlSessionFactory factory;
private static ThreadLocal<SqlSession> local=new ThreadLocal<>();
static{
try {
factory=new SqlSessionFactoryBuilder()
.build(
MyBatisUtil.class
.getClassLoader()
.getResourceAsStream("mybatis-config.xml")
);
} catch (Exception e) {
throw new ExceptionInInitializerError("MyBatisUtil初始化失败"+e.getMessage());
}
}
public static SqlSession getSession(){
SqlSession session = local.get();
if(session==null){
session = factory.openSession();
local.set(session);
}
return session;
}
public static void close(){
SqlSession session = local.get();
if(session!=null){
session.close();
local.remove();
}
}
}
共有三种方式
方法1:xml进行数据操作
方法2:在dao层用注解的方式
方法3:采取xml和dao层接口组合使用的方法。显然 ,后者更加简单。
方法1:只需要xml
(过时,只需要调用xml文件接收参数执行sql,可抽离出namespace作为statement变量)
userMapper.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指定唯一的id,通常设置成包名+sql映射的文件名-->
<mapper namespace="com.xxx.xxx.dao.DserDao">
<!-- 这里namespace不建议写xml文件全名,这种方式已过时,建议写接口全名,使用面向接口的优秀方式 -->
<!-- parameterType指明查询时使用的参数类型。如果参数只有1个则用简单类型,参数为多个时可用Map集合或实体对象,占位符必须用对象的属性名;
resultType表示查询结果将要封装成的实体类,也可以为对象类型、Map类型、基本类型-->
<select id="selectOneUser" resultType="com.xxx.xxx.entity.User" parameterType="int">
select * from pcmc_user where id = #{id}
</select>
useGeneratedKeys 设置保存时返回主键,true 开启,自动封装到对象中对应的属性,默认是false
keyProperty 指定对象的哪个属性的主键
<insert id="insertUser" parameterType="com.xxx.xxx.entity.User" useGeneratedKeys="true" keyProperty="id">
insert into pcmc_user(name, age) values(#{name}, #{age})
</insert>
<delete id="deleteUser">
delete from pcmc_user where id=#{id}
</delete>
<update id="updateUser" parameterType="com.xxx.xxx.entity.User" >
update pcmc_user set nam e= #{name},age = #{age} where id = #{id}
</update>
<select id="selectAllUser" resultType="com.xxx.xxx.entity.User">
select * from pcmc_user
</select>
<update id="dropTable">
drop table tableName
</update>
<update id="truncate" >
truncate table tableName
</update>
</mapper>
如果报错提示说没有 mapper.xml 文件
现在 pom.xml 中 build 标签下添加固定代码
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
Test 文件夹下新建 Test.java
public class Test {
public static void main(String[] args) throws Exception{
SqlSession session = MyBatisUtil.getSqlSession();//至此得到一个session
//Unhandled Exception:java.io.IOException 是因为少了throws Exception或者try/catch
//org.apache.ibatis.binding.BindingException: Type interface xxx is not known to the MapperRegistry
//上面的错误时因为namespace和接口名不相同,必须改为相同
String namespace = "com.xxx.xxx.mapper.userMapper.";//注意后面有一个点,为了和后面的mapper文件中的id连接
String statement4 = namespace+"selectOneUser";
User user = session.selectOne(statement4,1);
//selectOne sql中需要一个参数就传一个,这里查出来几个字段,都会按照实体类构造方法按顺序进行赋值
session.commit();
System.out.println("selectOne:"+user);
String statement1 = namespace+"insertUser";//映射sql的标识字符串
System.out.print(User);//此时没有设置id,id为null
int insert = session.insert(statement1,new User(10,"张三",18));
//insert 这里为什么插入后id并不是指定的10,因为该namespace中sql语句中没有插入id字段,而建表时主键id是自动增长的。
session.commit(); //默认增删改 必须手动提交提交事务
System.out.println("insert:"+insert);
System.out.print(User);//此时id有值,因为设置了useGeneratedKeys 和 keyProperty
String statement2 = namespace+"deleteUser";
int delete = session.delete(statement2,2);
session.commit();
System.out.println("delete:"+delete);
String statement3 = namespace+"updateUser";
int update = session.update(statement3,new User(1,"林更新",18));
session.commit();
System.out.println("update:"+update);
String statement5 = namespace+"selectAllUser";
List<User> list = session.selectList(statement5);
session.commit();
System.out.println("selectList:"+list);
String statement6 = namespace+"drop";
int update = session.update(statement6, "tableName");
session.commit();
System.out.println("update:"+update);
String statement7 = namespace+"truncate";
int update = session.update(statement7, "tableName");
session.commit();
System.out.println("update:"+update);
session.close();//必须释放session
}
}
方式2:xml+interface
xml 写法不变,增加 interface,
(需要xml和interface,namespace要和接口全名相同,建议使用此种方式)
public interface UserDao {
public List<User> selectUser() throws Exception;
}
Test.java
UserDao mapper = session.getMapper(UserDao.class);
List<User> list = mapper.selectUser();
方式3:interface和anotation
(只需要interface,注解将sql写在方法上,当有注解时,默认使用方式三,但只适用简单sql)
1,mapper包下(建议如此)新建同名接口
public interface UserDao {
//根据接口全类名找到同名namespace来对应mapper.xml的namespace
//方法名也要和mapper文件中id对应mapper.xml的<select>的id
@Insert ( "insert into pcmc_user(name, age) values(#{name}, #{age})" )
public int insertUser(User user) throws Exception;
@Delete ( "delete from pcmc_user where id=#{id}" )
public int deleteUser(int id) throws Exception;
@Update ( "update pcmc_user set name=#{name},age=#{age} where id=#{id}" )
public int updateUser (User user,int id) throws Exception;
@Select ( "select * from pcmc_user where id = #{id}" )
public User selectOneUser(int id) throws Exception;
@Select ( "select * from pcmc_user" )
public List<User> selectAllUser() throws Exception;
}
2,注册接口文件
如果使用 resource属性注册xml文件,按住Ctrl会提示红色错误,但是其实不影响,注册仍然会成功
<mappers>
<!-- package 注册包下面的所有Mapper接口 -->
<!-- <package name="com.xxx.xxx.mapperinterface"/> -->
<!-- resource属性 注册单个相对于类路径的Mapper.xml文件 -->
<mapper resource="com/xxx/xxx/mapper/UserMapper.xml"/>
<!-- url属性 注册一个绝对路径的的Mapper.xml文件 -->
<!-- <mapper url="file:///E:/UserMapper.xml"/> -->
<!-- class属性 注册一个Mapper接口,接口必须与mapper.xml文件名同名,且同路径下 -->
<!-- <mapper class="com.xxx.xxx.interface.UserMapper"/> -->
</mappers>
3,Test.java同方式2Test.java
SqlSession session = MyBatisUtil.getSqlSession();//得到一个session
//Unhandled Exception:java.io.IOException 是因为少了throws Exception或者try/catch
UserMapper userMapper = session.getMapper(UserMapper.class);
int num = userMapper.insertUser( new User(87,"Bob",30) );//insertUser等于方法名
session.commit();
List<User> list = userMapper.selectAllUser();
System.out.println(list);
useGeneratedKeys="true"
<insert id="insertUser" parameterType="com.huawei.cpt.vo.User" useGeneratedKeys="true" keyProperty="id">
insert into user (id,name,age) values(#{id},"Dandy","123456@a")
</insert>
User类的id为主键,这里useGeneratedKeys="true"表示需要使用自增这个功能,keyProperty="id"表示把自增值取到后存入参数对象的id属性中,用于sql中赋值,所以该实体类必须有该属性,且有setter方法;既然从表里取自增值,那么表必须设置为自增。
AUTO_INCREMENT
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT, --这里表示使用自增,步长默认1
`name` varchar(255) DEFAULT NULL,
`age` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;
/* 假设已存在的数据中字段id中的最大值为9,而创建表的时候AUTO_INCREMENT=12
则下次通过程序往表中insert数据,且没有指定字段id的值时,id将从12开始计算起,而不是10
这个功能有什么作用呢?比如有些数据原来是写死的,没有记录到数据库中,后来由于需求变化需要做成动态管理,需要保存到数据库中,
而原来有部分app_id已经被使用了,不能用于其它的,此时AUTO_INCREMENT就被派上用场了。
不使用指定的下次自增初始值的话,有可能新插入的数据与旧数据主键冲突,
所以AUTO_INCREMENT可以直接自定义一个较大值,避免主键发生冲突 */
假设,id此时自增到了10,然后手动插入一条记录,id为15,继续使用程序插入数据,会使用当前自增值,此时是11还是15,答案是:15,自增值会自动取最大值。
selectKey
查出一个随机数,作为user实体类的id属性进行赋值,然后insert into中取到这个id值进行数据插入;
所以User类中必须有id属性,且有setter方法,resultType也必须和User的id类型对应;
selectKey也有注解,但注解适用简单sql,就不研究了。太low
<insert id="insertUser" parameterType="com.huawei.cpt.vo.User">
<selectKey keyProperty="id" order="BEFORE" resultType="int">
select CEILING(RAND()*10000)
</selectKey>
insert into user (id, name, age) values (#{id}, #{name}, #{age})
</insert>