import com.imooc.stream.domain.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.cursor.Cursor;
@Mapper
public interface UserMapper {
/**
* 流式查询的好处是能够降低内存使用。
* 流式查询的过程当中,数据库连接是保持打开状态的,
* 因此要注意的是:执行一个流式查询后,数据库访问框架就不负责关闭数据库连接了,需要应用在取完数据后自己关闭
* @param limit
* @return
*/
@Select("select * from user limit #{limit}")
Cursor<User> scan(@Param("limit") int limit);
}
import com.imooc.stream.dao.UserMapper;
import com.imooc.stream.domain.User;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cursor.Cursor;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.io.IOException;
@Slf4j
@RestController
public class UserController {
@Resource
private SqlSessionFactory sqlSessionFactory;
@Resource
private UserMapper userMapper;
@Autowired
private TransactionTemplate transactionTemplate;
@GetMapping("foo/scan/1/{limit}")
public void scanUser(@PathVariable("limit") int limit) {
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
Cursor<User> cursor = sqlSession.getMapper(UserMapper.class).scan(limit);
cursor.forEach(e -> {});
}catch (Exception e){
log.error("获取数据错误:{}",e);
}
}
@GetMapping("foo/scan/2/{limit}")
public void scanFoo2(@PathVariable("limit") int limit) {
transactionTemplate.execute(status -> {
try (Cursor<User> cursor = userMapper.scan(limit)) {
cursor.forEach(e -> { });
} catch (IOException e) {
log.error("获取数据错误:{}",e);
}
return null;
});
}
}
1.Redis Desktop Manager 地址:https://redisdesktop.com/
2.medis 地址:http://getmedis.com/
3.AnotherRedisDesktopManager 地址:https://github.com/qishibo/AnotherRedisDesktopManager
4.FastoRedis 地址:https://fastoredis.com/
5.RedisPlus 地址:https://gitee.com/MaxBill/RedisPlus
6.Red 地址:Mac用户可以去app store里面搜
7.Redis Insight 地址:https://redislabs.com/redisinsight/
8.Iedis2 地址:IDEA插件
xml工具类
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.*;
@Slf4j
public class JaxbUtils {
//xml to java
public static <T> T jaxbReadXml(Class<T> clazz, byte[] data) {
InputStream inputStream;
try {
JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
inputStream = new ByteArrayInputStream(data);
return (T) unmarshaller.unmarshal(inputStream);
} catch (Exception e) {
log.error("xml to java fail!", e);
}
return null;
}
//java to xml
public static <T> byte[] jaxbWriteXml(Class<T> clazz, T object) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
Marshaller marshaller = jaxbContext.createMarshaller();
//编码格式
marshaller.setProperty(Marshaller.JAXB_ENCODING,"UTF-8");
//是否格式化生成的xml串
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
//是否省略xml头信息
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, false);
marshaller.marshal(object, byteArrayOutputStream);
byte[] data = byteArrayOutputStream.toByteArray();
return data;
} catch (Exception e) {
log.error("java to xml fail!", e);
}
return null;
}
}
import com.google.common.collect.Lists;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;
public abstract class BeanJoinUtils {
private BeanJoinUtils() {}
public static <Source, Id, Other> List<Source> innerJoin(
List<Source> source,
Function<Source, Id> sourceIdFunc,
Function<Set<Id>, Map<Id, Other>> otherGetter,
BiConsumer<Source, Other> targetSetter
) {
Set<Id> keys = source.stream().map(sourceIdFunc).collect(Collectors.toSet());
Map<Id, Other> otherMap = otherGetter.apply(keys);
if (otherMap != null) {
return source.stream().filter(item -> {
Id id = sourceIdFunc.apply(item);
if (id != null) {
Other other = otherMap.get(id);
if (other != null) {
targetSetter.accept(item, other);
return true;
}
}
return false;
}).collect(Collectors.toList());
} else {
return Lists.newArrayList();
}
}
public static <Source, Id, Other> void leftJoin(
List<Source> source,
Function<Source, Id> sourceIdFunc,
Function<Set<Id>, Map<Id, Other>> otherGetter,
BiConsumer<Source, Other> targetSetter
) {
Set<Id> keys = source.stream().map(sourceIdFunc).collect(Collectors.toSet());
Map<Id, Other> otherMap = otherGetter.apply(keys);
if (otherMap != null) {
source.forEach(item -> {
Id id = sourceIdFunc.apply(item);
Other other = otherMap.get(id);
if (other != null) {
targetSetter.accept(item, other);
}
});
}
}
}
获取汉字首字母工具类
import com.github.stuxuhai.jpinyin.PinyinFormat;
import com.github.stuxuhai.jpinyin.PinyinHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@Slf4j
public class PinyinUtils {
/**
* 取得给定汉字第一个字的拼音
* @param chinese 给定的汉字
* @return 第一个汉字的拼音
*/
public static String getFirstChsLetter(String chinese) {
try {
if(StringUtils.isEmpty(chinese)){
return "";
}
chinese = chinese.substring(0, 1);
return PinyinHelper.convertToPinyinString(chinese, " ", PinyinFormat.WITHOUT_TONE);
} catch (Exception e){
log.error("拼音获取异常:{}",e);
}
return "";
}
/**
* 获取汉语单词中每个汉字的大写首字母
* 单词中的数字和字母不处理,原样返回
* @param chs
* @return
*/
public static String getChsAcronym(String chs) {
if (StringUtils.isEmpty(chs)) {
return "";
}
StringBuilder convert = new StringBuilder();
for (int i = 0 ; i < chs.length(); i++) {
String chinese = String.valueOf(chs.charAt(i));
if ("^[A-Za-z0-9]".matches(chinese)){
convert.append(chinese);
continue;
}
convert.append(getFirstChsLetter(chinese), 0, 1);
}
return convert.toString().toUpperCase();
}
}
延时工具类
import java.util.Random;
import java.util.concurrent.TimeUnit;
/**
* 重新加载 DataSource 的时候设定一个延时,防止同一时间大量的 Connection 对数据库服务器造成冲击。
*/
public class SmoothReload {
public static final int SLEEP_TIME = 100;
private static final long DEFAULT_MAX_MILLISECOND_INTERVAL = 1000;
private static Random rnd = new Random();
private long maxMillisecondInterval;
private long randomInterval = 0;
private long startMillisecond;
public SmoothReload() {
this(DEFAULT_MAX_MILLISECOND_INTERVAL);
}
public SmoothReload(long maxMillisecondInterval) {
this.maxMillisecondInterval = maxMillisecondInterval;
this.startMillisecond = System.currentTimeMillis();
initRandomInterval();
}
public void initRandomInterval() {
this.randomInterval = (long) (rnd.nextDouble() * maxMillisecondInterval);
}
public void waitForReload() {
if (maxMillisecondInterval <= 0) {
return;
}
while (startMillisecond + randomInterval > System.currentTimeMillis()) {
try {
TimeUnit.MILLISECONDS.sleep(SLEEP_TIME);
} catch (InterruptedException ignore) {
}
}
}
}
stream操作工具类
import java.io.*;
public class StreamUtil {
private static final int DEFAULT_BUFFER_SIZE = 8192;
public StreamUtil() {
}
public static void io(InputStream in, OutputStream out) throws IOException {
io(in, out, -1);
}
public static void io(InputStream in, OutputStream out, int bufferSize) throws IOException {
if (bufferSize == -1) {
bufferSize = 8192;
}
byte[] buffer = new byte[bufferSize];
int amount;
while((amount = in.read(buffer)) >= 0) {
out.write(buffer, 0, amount);
}
}
public static void io(Reader in, Writer out) throws IOException {
io(in, out, -1);
}
public static void io(Reader in, Writer out, int bufferSize) throws IOException {
if (bufferSize == -1) {
bufferSize = 4096;
}
char[] buffer = new char[bufferSize];
int amount;
while((amount = in.read(buffer)) >= 0) {
out.write(buffer, 0, amount);
}
}
public static OutputStream synchronizedOutputStream(OutputStream out) {
return new StreamUtil.SynchronizedOutputStream(out);
}
public static OutputStream synchronizedOutputStream(OutputStream out, Object lock) {
return new StreamUtil.SynchronizedOutputStream(out, lock);
}
public static String readText(InputStream in) throws IOException {
return readText(in, null, -1);
}
sql脚本语言解析
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public final class Splitters {
public static StringSplitter by(char delimiter) {
return new StringSplitter(delimiter);
}
public static MapSplitter by(char pairSeparator, char keyValueSeparator) {
return new MapSplitter(pairSeparator, keyValueSeparator);
}
public static StringSplitter by(String delimiter) {
return new StringSplitter(delimiter);
}
public static class MapSplitter {
private char m_pairSeparator;
private char m_keyValueSeparator;
private boolean m_trim;
MapSplitter(char pairSeparator, char keyValueSeparator) {
m_pairSeparator = pairSeparator;
m_keyValueSeparator = keyValueSeparator;
}
protected void doCharSplit(String str, Map<String, String> map) {
int len = str.length();
StringBuilder key = new StringBuilder(len);
StringBuilder value = new StringBuilder(len);
boolean inKey = true;
for (int i = 0; i < len; i++) {
char ch = str.charAt(i);
if (ch == m_keyValueSeparator && inKey) {
inKey = false;
} else if (ch == m_pairSeparator) {
if (key.length() > 0) {
if (m_trim) {
map.put(key.toString().trim(), value.toString().trim());
} else {
map.put(key.toString(), value.toString());
}
}
key.setLength(0);
value.setLength(0);
inKey = true;
} else {
if (inKey) {
key.append(ch);
} else {
value.append(ch);
}
}
}
if (!inKey && key.length() > 0) {
if (m_trim) {
map.put(key.toString().trim(), value.toString().trim());
} else {
map.put(key.toString(), value.toString());
}
}
}
public Map<String, String> split(String str) {
return split(str, new LinkedHashMap<String, String>());
}
public Map<String, String> split(String str, Map<String, String> map) {
if (str != null) {
doCharSplit(str, map);
}
return map;
}
public MapSplitter trim() {
m_trim = true;
return this;
}
}
public static class StringSplitter {
private char m_charDelimiter;
private String m_stringDelimiter;
private boolean m_trim;
private boolean m_noEmptyItem;
StringSplitter(char delimiter) {
m_charDelimiter = delimiter;
}
StringSplitter(String delimiter) {
m_stringDelimiter = delimiter;
}
protected void doCharSplit(String str, List<String> list) {
char delimiter = m_charDelimiter;
int len = str.length();
StringBuilder sb = new StringBuilder(len);
for (int i = 0; i < len + 1; i++) {
char ch = i == len ? delimiter : str.charAt(i);
if (ch == delimiter) {
String item = sb.toString();
sb.setLength(0);
if (m_trim) {
item = item.trim();
}
if (m_noEmptyItem && item.length() == 0) {
continue;
}
list.add(item);
} else {
sb.append(ch);
}
}
}
protected void doStringSplit(String source, List<String> list) {
String delimiter = m_stringDelimiter;
int len = delimiter.length();
int offset = 0;
int index = source.indexOf(delimiter, offset);
while (true) {
String part;
if (index == -1) { // last part
part = source.substring(offset);
} else {
part = source.substring(offset, index);
}
if (m_trim) {
part = part.trim();
}
if (!m_noEmptyItem || part.length() > 0) {
list.add(part);
}
if (index == -1) { // last part
break;
} else {
offset = index + len;
index = source.indexOf(delimiter, offset);
}
}
}
public StringSplitter noEmptyItem() {
m_noEmptyItem = true;
return this;
}
public List<String> split(String str) {
return split(str, new ArrayList<String>());
}
public List<String> split(String str, List<String> list) {
if (str != null) {
if (m_charDelimiter > 0) {
doCharSplit(str, list);
} else if (m_stringDelimiter != null) {
doStringSplit(str, list);
}
}
return list;
}
public StringSplitter trim() {
m_trim = true;
return this;
}
}
}
public enum SqlType {
SELECT(true, true, false, 0), //
INSERT(false, false, true, 1), //
UPDATE(false, false, true, 2), //
DELETE(false, false, true, 3), //
SELECT_FOR_UPDATE(false, true, true, 4), //
REPLACE(false, false, true, 5), //
TRUNCATE(false, false, true, 6), //
CREATE(false, false, true, 7), //
DROP(false, false, true, 8), //
LOAD(false, false, true, 9), //
MERGE(false, false, true, 10), //
SHOW(true, true, false, 11), //
EXECUTE(false, false, true, 12), //
SELECT_FOR_IDENTITY(false, true, false, 13), //
EXPLAIN(true, true, false, 14), //
ALTER(false, false, true, 15), //
UNKNOWN_SQL_TYPE(false, false, true, -100); //
private boolean isRead;
private boolean isQuery;
private boolean isWrite;
private int i;
SqlType(boolean isRead, boolean isQuery, boolean isWrite, int i) {
this.isRead = isRead;
this.isQuery = isQuery;
this.isWrite = isWrite;
this.i = i;
}
public int value() {
return this.i;
}
public boolean isRead() {
return isRead;
}
public boolean isQuery() {
return isQuery;
}
public boolean isWrite() {
return isWrite;
}
public static SqlType valueOf(int i) {
for (SqlType t : values()) {
if (t.value() == i) {
return t;
}
}
throw new IllegalArgumentException("Invalid SqlType:" + i);
}
}
import org.apache.commons.lang3.StringUtils;
public final class SqlUtils {
private static final String SELECT_KEY = "select";
private static final String INSERT_KEY = "insert";
private static final String UPDATE_KEY = "update";
private static final String DELETE_KEY = "delete";
private static final String SHOW_KEY = "show";
private static final String REPLACE_KEY = "replace";
private static final String TRUNCATE_KEY = "truncate";
private static final String CREATE_KEY = "create";
private static final String DROP_KEY = "drop";
private static final String LOAD_KEY = "load";
private static final String MERGE_KEY = "merge";
private static final String EXPLAIN_KEY = "explain";
private static final String EXECUTE_KEY = "call";
private static final String IDENTITY_PATTERN = "@@identity";
private static final String LAST_INSERT_PATTERN = "last_insert_id(";
private static final String FOR_PATTERN = "for";
private static final String UPDATE_PATTERN = "update";
private static final String ALTER_PATTERN = "alter";
public static SqlType getSqlType(String sql) {
if (StringUtils.isBlank(sql)) {
return SqlType.UNKNOWN_SQL_TYPE;
}
SqlType sqlType;
String lowerSql = sql.toLowerCase();
boolean inComment = false;
int begin = 0;
// skip spaces and hint
for (; begin < lowerSql.length(); ++begin) {
char currentChar = lowerSql.charAt(begin);
if (!inComment) {
if (currentChar == '/') {
inComment = true;
} else if (currentChar > ' ') {
break;
}
} else if (currentChar == '/') {
inComment = !inComment;
}
}
if (lowerSql.length() - begin < EXECUTE_KEY.length()) {
return SqlType.UNKNOWN_SQL_TYPE;
}
// capture the first word
switch (lowerSql.charAt(begin)) {
case 's':
if (lowerSql.charAt(begin + 1) == 'e') {
sqlType = selectHandler(lowerSql, begin);
} else {
sqlType = showHandler(lowerSql, begin);
}
break;
case 'i':
sqlType = insertHandler(lowerSql, begin);
break;
case 'u':
sqlType = updateHandler(lowerSql, begin);
break;
case 'd':
if (lowerSql.charAt(begin + 1) == 'e') {
sqlType = deleteHandler(lowerSql, begin);
} else {
sqlType = dropHandler(lowerSql, begin);
}
break;
case 'r':
sqlType = replaceHandler(lowerSql, begin);
break;
case 't':
sqlType = truncateHandler(lowerSql, begin);
break;
case 'c':
sqlType = createHandler(lowerSql, begin);
break;
case 'l':
sqlType = loadHandler(lowerSql, begin);
break;
case 'm':
sqlType = mergeHandler(lowerSql, begin);
break;
case 'e':
sqlType = explainHandler(lowerSql, begin);
break;
case 'a':
sqlType = alterHandler(lowerSql, begin);
break;
default:
sqlType = executeHandler(lowerSql, begin);
break;
}
return sqlType;
}
private static SqlType alterHandler(String lowerSql, int begin) {
if (isStartWithKeyWord(lowerSql, begin, ALTER_PATTERN)) {
return SqlType.ALTER;
}
return SqlType.UNKNOWN_SQL_TYPE;
}
private static SqlType selectHandler(String sql, int begin) {
if (isStartWithKeyWord(sql, begin, SELECT_KEY)) {
if (endsWithForUpdate(sql)) {
return SqlType.SELECT_FOR_UPDATE;
}
boolean inWord = false;
boolean inCommon = false;
begin = begin + SELECT_KEY.length();
for (; begin < sql.length(); ++begin) {
char ch = sql.charAt(begin);
switch (ch) {
case 'l':
if (!inCommon && !inWord && isKeyWord(sql, begin, LAST_INSERT_PATTERN)) {
return SqlType.SELECT_FOR_IDENTITY;
}
begin += LAST_INSERT_PATTERN.length();
break;
case '@':
if (!inCommon && !inWord && isKeyWord(sql, begin, IDENTITY_PATTERN)) {
return SqlType.SELECT_FOR_IDENTITY;
}
begin += IDENTITY_PATTERN.length();
break;
case '/':
inCommon = !inCommon;
if (inWord) {
inWord = false;
}
break;
case ' ':
case '\r':
case '\n':
case '\t':
case ',':
if (inWord) {
inWord = false;
}
break;
default:
if (!inCommon && !inWord) {
inWord = true;
}
break;
}
}
return SqlType.SELECT;
}
return SqlType.UNKNOWN_SQL_TYPE;
}
private static SqlType insertHandler(String sql, int begin) {
if (isStartWithKeyWord(sql, begin, INSERT_KEY)) {
return SqlType.INSERT;
}
return SqlType.UNKNOWN_SQL_TYPE;
}
private static SqlType updateHandler(String sql, int begin) {
if (isStartWithKeyWord(sql, begin, UPDATE_KEY)) {
return SqlType.UPDATE;
}
return SqlType.UNKNOWN_SQL_TYPE;
}
private static SqlType deleteHandler(String sql, int begin) {
if (isStartWithKeyWord(sql, begin, DELETE_KEY)) {
return SqlType.DELETE;
}
return SqlType.UNKNOWN_SQL_TYPE;
}
private static SqlType showHandler(String sql, int begin) {
if (isStartWithKeyWord(sql, begin, SHOW_KEY)) {
return SqlType.SHOW;
}
return SqlType.UNKNOWN_SQL_TYPE;
}
private static SqlType replaceHandler(String sql, int begin) {
if (isStartWithKeyWord(sql, begin, REPLACE_KEY)) {
return SqlType.REPLACE;
}
return SqlType.UNKNOWN_SQL_TYPE;
}
private static SqlType truncateHandler(String sql, int begin) {
if (isStartWithKeyWord(sql, begin, TRUNCATE_KEY)) {
return SqlType.TRUNCATE;
}
return SqlType.UNKNOWN_SQL_TYPE;
}
private static SqlType createHandler(String sql, int begin) {
if (isStartWithKeyWord(sql, begin, CREATE_KEY)) {
return SqlType.CREATE;
}
return SqlType.UNKNOWN_SQL_TYPE;
}
private static SqlType dropHandler(String sql, int begin) {
if (isStartWithKeyWord(sql, begin, DROP_KEY)) {
return SqlType.DROP;
}
return SqlType.UNKNOWN_SQL_TYPE;
}
private static SqlType loadHandler(String sql, int begin) {
if (isStartWithKeyWord(sql, begin, LOAD_KEY)) {
return SqlType.LOAD;
}
return SqlType.UNKNOWN_SQL_TYPE;
}
private static SqlType mergeHandler(String sql, int begin) {
if (isStartWithKeyWord(sql, begin, MERGE_KEY)) {
return SqlType.MERGE;
}
return SqlType.UNKNOWN_SQL_TYPE;
}
private static SqlType explainHandler(String sql, int begin) {
if (isStartWithKeyWord(sql, begin, EXPLAIN_KEY)) {
return SqlType.EXPLAIN;
}
return SqlType.UNKNOWN_SQL_TYPE;
}
private static SqlType executeHandler(String sql, int begin) {
boolean inWord = false;
boolean inCommon = false;
for (; begin < sql.length(); ++begin) {
char ch = sql.charAt(begin);
switch (ch) {
case 'c':
if (!inCommon && !inWord && isKeyWord(sql, begin, EXECUTE_KEY)) {
char nextCh = sql.charAt(begin + EXECUTE_KEY.length());
if (isControlChar(nextCh)) {
return SqlType.EXECUTE;
}
begin = begin + EXECUTE_KEY.length();
}
break;
case '/':
inCommon = !inCommon;
if (inWord) {
inWord = false;
}
break;
case ' ':
case '\r':
case '\n':
case '\t':
case ',':
if (inWord) {
inWord = false;
}
break;
default:
if (!inCommon) {
if (Character.isLetter(ch)) {
inWord = true;
}
}
break;
}
}
return SqlType.UNKNOWN_SQL_TYPE;
}
public static boolean isStartWithKeyWord(String sql, int begin, String word) {
if (isKeyWord(sql, begin, word)) {
if (sql.length() > begin + word.length()) {
char nextCh = sql.charAt(begin + word.length());
if (!isControlChar(nextCh) && nextCh != '/') {
return false;
}
}
return true;
}
return false;
}
private static boolean isKeyWord(String sql, int begin, String word) {
int end = begin;
for (int i = 0; i < word.length(); ++i, ++end) {
if (end >= sql.length() || word.charAt(i) != sql.charAt(end)) {
return false;
}
}
return true;
}
private static boolean isControlChar(char ch) {
if (' ' == ch || '\r' == ch || '\n' == ch || '\t' == ch) {
return true;
}
return false;
}
private static boolean endsWithForUpdate(String sql) {
int sqlPos = sql.length() - 1;
for (; sqlPos > 0; --sqlPos) {
char ch = sql.charAt(sqlPos);
if (!isControlChar(ch) && ch != ';') {
break;
}
}
for (int i = UPDATE_PATTERN.length() - 1; i >= 0; --i, --sqlPos) {
if (sqlPos <= 0 || sql.charAt(sqlPos) != UPDATE_PATTERN.charAt(i)) {
return false;
}
}
for (; sqlPos > 0; --sqlPos) {
if (!isControlChar(sql.charAt(sqlPos))) {
break;
}
}
if (sqlPos > 0) {
for (int i = FOR_PATTERN.length() - 1; i >= 0; --i, --sqlPos) {
if (sqlPos <= 0 || sql.charAt(sqlPos) != FOR_PATTERN.charAt(i)) {
return false;
}
}
}
if (sqlPos <= 0 || !isControlChar(sql.charAt(sqlPos))) {
return false;
}
return true;
}
public static String buildSqlType(String sql) {
return getSqlType(sql).name();
}
}